资源预览内容
第1页 / 共34页
第2页 / 共34页
第3页 / 共34页
第4页 / 共34页
第5页 / 共34页
第6页 / 共34页
第7页 / 共34页
第8页 / 共34页
第9页 / 共34页
第10页 / 共34页
亲,该文档总共34页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
第第1111章章 类间关系的实现类间关系的实现11.1 一般一般特殊关系的实现特殊关系的实现11.2 多态性与虚函数多态性与虚函数11.3 整体整体部分关系的实现部分关系的实现11.4 关联关系的实现关联关系的实现11.5 关于类层次的总结关于类层次的总结学习目的:学习目的: 掌握类间关系的掌握类间关系的C+C+实现;实现; 了解多态性与虚函数的概念。了解多态性与虚函数的概念。11.1 11.1 一般一般特殊关系的实现特殊关系的实现11.1.1类的继承与派生类的继承与派生11.1.2赋值兼容规则赋值兼容规则11.1.3两义性与作用域分辨两义性与作用域分辨C+C+提供了描述一般提供了描述一般特殊关系的语法,在特殊关系的语法,在C+C+中称为类的中称为类的派生或继承,通常分为单一继承和多重继承。在派生或继承,通常分为单一继承和多重继承。在C+ C+ 中常中常把一般把一般特殊关系中的一般类称为父类,而把特殊类称为特殊关系中的一般类称为父类,而把特殊类称为子类。子类。11.1.111.1.1类的继承与派生类的继承与派生1. 单一继承单一继承派生类说明格式:派生类说明格式:class : ;派生类初始化构造函数格式如下:派生类初始化构造函数格式如下:ClassName:ClassName(ArgList0) : DerivedClassName(ArgList1) 例例11.1 11.1 描述由矩形、正方形组成的平面图形系统描述由矩形、正方形组成的平面图形系统 类体中的成员为子类所特有的数据成员和成员函数,虽然没有在子类中类体中的成员为子类所特有的数据成员和成员函数,虽然没有在子类中写明所继承的父类成员,但是父类成员在一定限制下属于子类。写明所继承的父类成员,但是父类成员在一定限制下属于子类。 矩形矩形长长宽宽位置位置求面积求面积求周长求周长求位置求位置正方形正方形求面积求面积求周长求周长求位置求位置边边 长长#include iostream.hclass CRectangle /矩形类矩形类 public: CPoint m_cpLocation;/图形所在位置图形所在位置 int m_nWidth;/图形的宽度图形的宽度 int m_nHeight;/图形的高度图形的高度 CRectangle(int nX, int nY, int nWidth, int nHeight); int GetArea();/求面积求面积 int GetPerimeter(); /求周长求周长 CPoint& GetPosition();/返回图形位置返回图形位置;CRectangle:CRectangle(int nX,int nY,int nW,int nH):m_cpLocation(nX,nY) m_nWidth=nW; m_nHeight=nH;int CRectangle:GetArea() return m_nWidth*m_nHeight; int CRectangle:GetPerimeter() return m_nWidth+m_nWidth+m_nHeight+m_nHeight; CPoint& CRectangle:GetPosition() return this-m_cpLocation; class CSquare : public CRectangle /正方形类,派生自矩形类正方形类,派生自矩形类 public: CSquare(int nX, int nY, int nEdge); int GetEdge(); /返回边长返回边长;CSquare:CSquare(int nX, int nY, int nEdge) : CRectangle(nX, nY, nEdge, nEdge) int CSquare:GetEdge() return m_nWidth; void main() CRectangle r(1,1,2,3); CSquare s(0,0,2); coutr.GetArea()endls.GetArea()endl;11.1.111.1.1类的继承与派生类的继承与派生2. 基类成员访问控制基类成员访问控制 有两个因素同时控制着派生类对基类成员的访问权限,这两个因素就是有两个因素同时控制着派生类对基类成员的访问权限,这两个因素就是基类类体中类成员的访问说明符,及派生类的派生方式。基类类体中类成员的访问说明符,及派生类的派生方式。基基类成成员在派生在派生类中的中的访问权限限成成类员类员派生方式派生方式privateprotectedpublicprivate不可不可访问访问私有私有私有私有protected不可不可访问访问保保护护保保护护public不可不可访问访问保保护护公有公有基类的基类的private成员将不被子类继承,且不能被子类成员访问。成员将不被子类继承,且不能被子类成员访问。private派生方式:派生方式:基类成员(基类成员(private类除外)作为子类的类除外)作为子类的private类类型成员。型成员。public派生方式:派生方式:基类成员(基类成员(private类除外)作为子类的相同类型类除外)作为子类的相同类型成员。成员。protected派生方式:派生方式: 基类成员(基类成员(private类除外)作为子类的类除外)作为子类的protected类型成员。类型成员。11.1.111.1.1类的继承与派生类的继承与派生3 多重继承多重继承 多重继承在多重继承在C+C+中实现方式如下:中实现方式如下:class : , ;派生类构造函数应该调用所有基类的构造函数对基类数据成员进行初始派生类构造函数应该调用所有基类的构造函数对基类数据成员进行初始化,格式如下:化,格式如下::(ArgList0) : (ArgList1), (ArgListn) #include iostream.h#include stdlib.h#include string.hclass CWnd; / 引用性说明引用性说明#define MAXTEXTBUFFER 0xffffclass CPoint private: int m_x; int m_y; 4 继承与派生示例继承与派生示例 public: CPoint(int x=0, int y=0) m_x=x; m_y=y; int GetX() return m_x; int GetY() return m_y; ;class WNDSTRUCT /本对象中含有窗口公共数据本对象中含有窗口公共数据 protected: char* m_pczWndName;/窗口名字窗口名字 /下述四个量表示窗口左上角和右下角的坐标下述四个量表示窗口左上角和右下角的坐标 CPoint m_cpTopLeft; CPoint m_cpBottomRight; /下述三个量用于建立窗口系统的树结构下述三个量用于建立窗口系统的树结构 CWnd* m_pParentWindow; /指向本窗口的父窗口指向本窗口的父窗口 CWnd* m_pChildFirst;/CWnd的指针数组,放着本窗口的子窗口的指针数组,放着本窗口的子窗口 CWnd* m_pSiblingFirst;/指向本窗口的兄弟窗口指向本窗口的兄弟窗口 char* m_pEditTextBuffer;/指向窗口编辑区文本缓冲区指向窗口编辑区文本缓冲区 WNDSTRUCT(const WNDSTRUCT& rWndArch) m_pczWndName=new charstrlen(rWndArch.m_pczWndName)+1; if(m_pczWndName=0) coutNo enough space!endl; exit(0); strcpy(m_pczWndName, rWndArch.m_pczWndName); WNDSTRUCT() delete m_pczWndName; ;class CScreenObject : virtual private WNDSTRUCT public: void MoveToWindow(const CPoint& cpWndPos, int nWidth, int nHeight) HideWindow(); m_cpTopLeft=cpWndPos; m_cpBottomRight=CPoint(m_cpTopLeft.GetX()+nWidth, m_cpBottomRight.GetY()+nHeight); RedrawWindow(); CScreenObject() delete m_pczWndName; void HideWindow() /*隐藏当前窗口隐藏当前窗口*/ void RedrawWindow() /*绘制并显示当前窗口绘制并显示当前窗口*/ ;class CEditText : virtual private WNDSTRUCT public: CEditText(WNDSTRUCT& rWndArch) : WNDSTRUCT(rWndArch) m_pEditTextBuffer=new charMAXTEXTBUFFER+1; if(m_pEditTextBuffer=0) coutNo enough space; exit(1); memset(m_pEditTextBuffer, 0, MAXTEXTBUFFER+1); CEditText() delete m_pEditTextBuffer; void TextCut(int nStart, int nEnd) char* TempStr=new charMAXTEXTBUFFER-nEnd; memset(m_pEditTextBuffer+nEnd, 0, MAXTEXTBUFFER-nEnd); memcpy(m_pEditTextBuffer+nEnd, TempStr, MAXTEXTBUFFER-nEnd); delete TempStr; /此处应该调用适当函数重新绘制编辑区显示内容此处应该调用适当函数重新绘制编辑区显示内容 /* TextPaste(), TextCopy() 等函数等函数 */;class CWindowTree : virtual private WNDSTRUCT public: CWindowTree(WNDSTRUCT& rWndArch) : WNDSTRUCT(rWndArch) void AddChild(CWnd* pChild) while(*m_pChildFirst!=0) +m_pChildFirst; *m_pChildFirst=pChild; /* 其他关于窗口树的操作其他关于窗口树的操作 */;class CWnd : public CWindowTree, public CEditText, public CScreenObject ; class CDerived : public CBase1, public CBase2 public: int b; CDerived() b=0x21; ;void main() CDerived obj; 11.1.111.1.1类的继承与派生类的继承与派生5. 派生类对象内存映像派生类对象内存映像 例例11.4class CBase public: int b0; CBase() b0=0x01; ;class CBase1 : public CBase public: int b1; CBase1() b1=0x11; ;class CBase2 : public CBase public: int b2; CBase2() b2=0x12; ;存储内容存储内容变量变量地地址址增增加加方方向向00 00 00 21b00 00 00 12b200 00 00 01b000 00 00 11b1起始地址起始地址00 00 00 01b0CBase2CBase2对象对象CBase1CBase1对象对象CDerivedCDerived对象对象11.1.211.1.2赋值兼容规则赋值兼容规则1. 派生类对象可以赋值给父类对象派生类对象可以赋值给父类对象对于对于例例11.4中的类,下列语句合法:中的类,下列语句合法:CBase b;CBase1 b1;b=b1;2. 2. 派生类的对象可以用于基类引用的初始化派生类的对象可以用于基类引用的初始化 对于对于 例例11.411.4,下列语句合法:,下列语句合法:CBase1 b1;CBase& refBase=b1;对于对于例例11.4下列语句合法:下列语句合法:CBase1 b1;CBase *pBaseObj=&b1;3. 3. 派生类对象的地址可以赋值给指向基类的指针派生类对象的地址可以赋值给指向基类的指针 存储内容存储内容变量变量00 00 00 11b1起始地址起始地址00 00 00 01b0CBase1CBase1对象对象CBaseCBase对象对象通过派生类通过派生类CBaselCBasel对象的对象的内存映像图可以看到这种内存映像图可以看到这种赋值的物理意义。赋值的物理意义。 11.1.311.1.3两义性与作用域分辨两义性与作用域分辨1. 作用域分辨作用域分辨如类的多个父类中具有相同名数据成员或成员函数,在引用该成员时如类的多个父类中具有相同名数据成员或成员函数,在引用该成员时可使用作用域分辨符可使用作用域分辨符 : : 来区分所引用的名字究竟属于哪个父类。来区分所引用的名字究竟属于哪个父类。 例例11.5class CBase1 public: void MyFunc() coutThis is CBase1s MyFuncendl; ;class CBase2 public: void MyFunc() coutThis is CBase2s MyFuncendl; ;class CDerived : public CBase1, public CBase2 public: void func() MyFunc(); /错误!错误! 两义性!两义性!;void main() CDerived obj; obj.func();显然,派生类显然,派生类CDerivedCDerived中函数中函数funcfunc()()对父类成员对父类成员函数函数MyFuncMyFunc()()的引用是具有二义性的,编译器无的引用是具有二义性的,编译器无法判断所要调用的是哪一个父类的成员函数,因法判断所要调用的是哪一个父类的成员函数,因此相应的语句出现语法错误。解决这种错误的办此相应的语句出现语法错误。解决这种错误的办法是在程序中使用作用域分辨符直接指明所要引法是在程序中使用作用域分辨符直接指明所要引用的是哪个类的用的是哪个类的MyFuncMyFunc()(),因此将派生类,因此将派生类CDerivedCDerived的定义改写如下:的定义改写如下:class CDerived :public CBase1, public CBase2 public: void func() CBase1:MyFunc(); /调用调用CBase1类的成员函数类的成员函数MyFunc() CBase2:MyFunc(); /调用调用CBase2类的成员函数类的成员函数MyFunc() ;11.1.311.1.3两义性与作用域分辨两义性与作用域分辨2. 支配规则支配规则如果类如果类Y Y是类是类X X的一个基类,则的一个基类,则X X中的成员中的成员namename支配基类中的同名成员。支配基类中的同名成员。如果在程序中要访问被支配的名字,可以使用作用域分辨符。如果在程序中要访问被支配的名字,可以使用作用域分辨符。 class A public: int a();class B : public virtual A public: int a();class C : public virtual A ;class D : public B, public C public: D() a();/ 无二义性无二义性. B:a() 支配支配 A:a. ;CBaseCBaseintint b bCBase1CBase1CBase2CBase2CDerivedCDerivedintint funcfunc()()CBaseCBaseintint b b从同一个类直接继承两次以上从同一个类直接继承两次以上11.1.311.1.3两义性与作用域分辨两义性与作用域分辨3. 虚基类虚基类多个父类由同一类派生,创建对象时内存中会有爷爷类多个实例(例多个父类由同一类派生,创建对象时内存中会有爷爷类多个实例(例11.4)。可采用两种方式消除二义性,其一使用)。可采用两种方式消除二义性,其一使用 :,其二将爷爷类作,其二将爷爷类作为虚基类,使创建对象时内存中只有爷爷类的一个实例。为虚基类,使创建对象时内存中只有爷爷类的一个实例。例例11.7 派生类的两个父类具有一个共同的虚基类。派生类的两个父类具有一个共同的虚基类。class CBase public: int b0; CBase() b0=0x01; ;class CBase1 : public virtual CBase public: int b1; CBase1() b1=0x11; ;class CBase2 : public virtual CBase public: int b2; CBase2() b2=0x12; ;class CDerived :public CBase1, public CBase2 public: int b; CDerived() b=0x21; ;void main() CDerived obj; 11.1.311.1.3两义性与作用域分辨两义性与作用域分辨3. 虚基类虚基类11.2 11.2 多态性与虚函数多态性与虚函数11.2.1 编译时刻的多态性编译时刻的多态性11.2.2 运行时刻的多态性运行时刻的多态性11.2.3 虚函数虚函数11.2.4 纯虚函数与抽象类纯虚函数与抽象类广义的多态性可以理解为一个名字具有多种语义。面向对象中的多态广义的多态性可以理解为一个名字具有多种语义。面向对象中的多态性是指不同类的对象对于同一消息的处理具有不同的实现性是指不同类的对象对于同一消息的处理具有不同的实现, ,在在C+C+中表中表现为同一形式的函数调用,可能调用不同的函数实现。现为同一形式的函数调用,可能调用不同的函数实现。C+C+的多态性可分为两类,一类称为的多态性可分为两类,一类称为编译时刻多态性编译时刻多态性,另一类称为,另一类称为运运行时刻多态性行时刻多态性。与之相应的概念有。与之相应的概念有静态联编静态联编(亦称静态绑定、静态集(亦称静态绑定、静态集束、静态束定等)、束、静态束定等)、动态联编动态联编(亦称动态绑定、动态集束、动态束定(亦称动态绑定、动态集束、动态束定等)。等)。 11.2.111.2.1 编译时刻的多态性编译时刻的多态性函数重载为一种常见的编译时刻多态性,编译时通过参数类型匹配,定函数重载为一种常见的编译时刻多态性,编译时通过参数类型匹配,定位所调用函数的具体实现,然后用该实现代码调用代替源程序中的函数位所调用函数的具体实现,然后用该实现代码调用代替源程序中的函数调用。调用。例例11.9 编译时刻多态性。编译时刻多态性。#include iostream.hconst float PI=float(3.14);class CPoint private: int m_x; int m_y; public: CPoint(int x=0, int y=0); void Area() coutHere is a points area: 0endl; ;CPoint:CPoint(int x, int y) m_x=x; m_y=y;class CCircle : public CPoint private: float m_nRadius; public: CCircle(int x=0, int y=0, float r=0) : CPoint(x, y) m_nRadius=r; void SetRadius(float r) m_nRadius=r; void Area() coutHere is a circles area: PI*m_nRadius*m_nRadiusendl; ;void main() CCircle c1; c1.Area();11.2.211.2.2运行时刻的多态性运行时刻的多态性运行时刻多态性的实现机制是动态联编,在程序运行时刻确定所要调用运行时刻多态性的实现机制是动态联编,在程序运行时刻确定所要调用的是哪个具体函数实现,这种联编形式的程序运行效率低于静态联编,的是哪个具体函数实现,这种联编形式的程序运行效率低于静态联编,因为要花额外开销去推测所调用的是哪一个函数。虽然动态联编的运行因为要花额外开销去推测所调用的是哪一个函数。虽然动态联编的运行效率低于静态联编,但是动态联编为程序的具体实现带来了巨大的灵活效率低于静态联编,但是动态联编为程序的具体实现带来了巨大的灵活性,使得对变化万千的问题空间对象的描述变得容易,使函数调用的风性,使得对变化万千的问题空间对象的描述变得容易,使函数调用的风格比较接近人类的习惯。格比较接近人类的习惯。例例11.10 运行时刻的多态性。运行时刻的多态性。#include iostream.hconst float PI=float(3.14);class CPoint private: int m_x; int m_y; public: CPoint(int x=0, int y=0); void Area() coutHere is a points area: 0endl; ;CPoint:CPoint(int x, int y) m_x=x; m_y=y;class CCircle : public CPoint private: float m_nRadius; public: CCircle(int x=0, int y=0, float r=0) : CPoint(x, y) m_nRadius=r; void SetRadius(float r) m_nRadius=r; void Area() coutHere is a circles area: PI*m_nRadius*m_nRadiusArea();11.2.311.2.3 虚函数虚函数类的一个成员函数被说明为虚函数表明它目前的具体实现仅仅是一种假类的一个成员函数被说明为虚函数表明它目前的具体实现仅仅是一种假设,只是一种适用于当前类的实现,在未来类的派生链条中有可能重新设,只是一种适用于当前类的实现,在未来类的派生链条中有可能重新定义这个成员函数的实现定义这个成员函数的实现 (override)。虚函数的使用方法如下:)。虚函数的使用方法如下:class vitual void MyFunction(); ;void :MyFunction() 当某一个成员函数在基类中被定义为虚函数,那么只要同名函数出现在当某一个成员函数在基类中被定义为虚函数,那么只要同名函数出现在派生类中,如果在类型、参数等方面均保持相同,那么,即使在派生类派生类中,如果在类型、参数等方面均保持相同,那么,即使在派生类中的相同函数前没有关键字中的相同函数前没有关键字virtual,它也被缺省地看作是一个虚函数,它也被缺省地看作是一个虚函数,但为保证风格统一,建议在派生类的虚函数前仍然添加关键字但为保证风格统一,建议在派生类的虚函数前仍然添加关键字virtual。11.2.311.2.3 虚函数虚函数不同语言环境实现虚不同语言环境实现虚函数的机制不同,下函数的机制不同,下面通过类面通过类CDerived的的派生介绍派生介绍Visual C+中如何实现虚函数。中如何实现虚函数。(程序见备注)(程序见备注)1 虚函数的实现虚函数的实现11.2.311.2.3 虚函数虚函数2 虚函数的使用虚函数的使用 虚函数的实现机制和调用方式与非虚函数不同,因此虚函数的使用具有特虚函数的实现机制和调用方式与非虚函数不同,因此虚函数的使用具有特殊性。殊性。虚函数的访问权限虚函数的访问权限 派生类中虚函数的访问权限并不影响派生类中虚函数的访问权限并不影响虚函数的动态联编,例如下面的程序实例虚函数的动态联编,例如下面的程序实例 例例11.1111.11,其中,其中派生类派生类CDerivedCDerived中重新定义了虚函数中重新定义了虚函数Func4()Func4(),在程序的运,在程序的运行中由于虚函数的机制,在行中由于虚函数的机制,在CBase:Func3()CBase:Func3()中调用中调用Func3()Func3()时会调用时会调用CDerived:Func3()CDerived:Func3(),而该函数的访问权限是私有,而该函数的访问权限是私有的。的。成员函数中调用虚函数成员函数中调用虚函数 在成员函数中可以直接调用相应在成员函数中可以直接调用相应类中定义或重新定义的虚函数,分析这类函数的调用次序类中定义或重新定义的虚函数,分析这类函数的调用次序时要注意成员函数的调用一般是隐式调用,应该将之看做时要注意成员函数的调用一般是隐式调用,应该将之看做是通过是通过thisthis指针的显式调用,参见下例:指针的显式调用,参见下例:例例11.11 在成员函数中调用虚函数。在成员函数中调用虚函数。#include iostream.hclass CBase public: void Func1() cout CBase:Func1= ; Func2(); void Func2() cout ; Func3(); virtual void Func3() cout ; Func4(); virtual void Func4() cout outendl; ; class CDerived : public CBase private: virtual void Func4() cout out endl; public: void Func1() cout Derived:Func1= ; CBase:Func2(); void Func2() cout Derived:Func2= ; Func3(); ;void main() CBase* pBase; CDerived dObj; pBase=&dObj; pBase-Func1(); dObj.Func1();11.2.311.2.3 虚函数虚函数class CBase1 public: virtual void MyFunc() coutCBase1:MyFuncendl; ;class CBase2 public: virtual void MyFunc() coutCBase2:MyFuncendl; ;class CDerived : public CBase1, public CBase2 public: virtual void MyFunc() coutCDerived:MyFuncMyFunc(); pB2-MyFunc(); 3. 多重继承与虚函数多重继承与虚函数程序中指向父类程序中指向父类CBase1、CBase2的指针的指针pB1、pB2分别被赋予了派分别被赋予了派生类生类CDerived对象的地址,由于对象的地址,由于MyFunc( )函数为虚函数,因此通过两个函数为虚函数,因此通过两个指针调用该函数的结果是都调用指针调用该函数的结果是都调用了派生类的函数了派生类的函数 CDerived:MyFunc( ) 。采用这种方式能够使前期程序设采用这种方式能够使前期程序设计人员调用后期程序设计人员所计人员调用后期程序设计人员所实现的具体函数。实现的具体函数。11.2.311.2.3 虚函数虚函数class CBase public: virtual void MyFunc1() ;class CDerived1 : virtual public CBase public: virtual void MyFunc1() coutCDerived1:MyFunc1endl; ; class CDerived2 : virtual public CBase public: virtual void MyFunc2() coutCDerived2:MyFunc2endl; MyFunc1(); ;3. 多重继承与虚函数多重继承与虚函数可以说明具有虚函数的虚基类,适当地使用这种方式能够提供作为父类的可以说明具有虚函数的虚基类,适当地使用这种方式能够提供作为父类的两个兄弟类实例之间的通信,是一种较好的通信方式两个兄弟类实例之间的通信,是一种较好的通信方式 。 class CDerived : virtual public CDerived1, virtual public CDerived2 ;void main() CDerived dObj; dObj.MyFunc2();11.2.311.2.3 虚函数虚函数#include iostream.h#include string.hclass CBase public: virtual CBase() coutCBase:CBase(); ;class CDerived : public CBase public: virtual CDerived() coutCDerived:CDerived()endl; ;void main() CBase* pB=new CDerived; delete pB;4. 虚析构函数虚析构函数析构函数可以被说明为虚函数,利用虚析构函数,删除对象时不必考虑对析构函数可以被说明为虚函数,利用虚析构函数,删除对象时不必考虑对象的类型(父类或子类),虚函数机制将保证调用适当的析构函数。象的类型(父类或子类),虚函数机制将保证调用适当的析构函数。 11.2.411.2.4纯虚函数与抽象类纯虚函数与抽象类软件系统的功能由类层次中的各类所实现,不同的类提供了相应层次的软件系统的功能由类层次中的各类所实现,不同的类提供了相应层次的功能实现,通过类的用户接口可以调用这些功能,人们通常所习惯的不功能实现,通过类的用户接口可以调用这些功能,人们通常所习惯的不是将功能在不同类层次的实现用不同的接口表示,而是将概念上相似的是将功能在不同类层次的实现用不同的接口表示,而是将概念上相似的功能用一个统一的接口功能用一个统一的接口在最顶层在最顶层表示,例如:一个系统可能提供了表示,例如:一个系统可能提供了“打打印印”这一功能,但这一功能,但“打印打印”对其各组成部分的含义不同,可能包括打印对其各组成部分的含义不同,可能包括打印文本文件、打印照片、打印图形等,这些打印功能的具体实现由各个类文本文件、打印照片、打印图形等,这些打印功能的具体实现由各个类提供,但对整个系统来讲它们应该具有相同的接口,在调用时应能够根提供,但对整个系统来讲它们应该具有相同的接口,在调用时应能够根据具体情况调用其具体实现。虚函数可以帮助我们做到这一点,若干概据具体情况调用其具体实现。虚函数可以帮助我们做到这一点,若干概念上相似的操作可以用一个虚函数描述,该虚函数在较高层次上表示一念上相似的操作可以用一个虚函数描述,该虚函数在较高层次上表示一种功能的接口,而在不同类中对该虚函数的重新定义就是该项功能不同种功能的接口,而在不同类中对该虚函数的重新定义就是该项功能不同层次上的实现,虚函数调用机制可保证虚函数的某个恰当的实现被调用。层次上的实现,虚函数调用机制可保证虚函数的某个恰当的实现被调用。也就是说,利用虚函数,可以使系统中多个相似的功能具有统一的接口,也就是说,利用虚函数,可以使系统中多个相似的功能具有统一的接口,改善了类的用户接口。方式如下:改善了类的用户接口。方式如下:class virtual (ArgList)=0; ;11.3 11.3 整体整体部分关系的实现部分关系的实现C+对整体对整体部分关系提供支持手段,对复合聚合,采用嵌入式对象的方部分关系提供支持手段,对复合聚合,采用嵌入式对象的方式,即属性的类型为类,例如消息窗口类可以如下定义:式,即属性的类型为类,例如消息窗口类可以如下定义:class CButton CButton() ;class CIcon CIcon() ;class CStudent CStudent(const char* pStudentName) ;class CGroup private: CStudent* m_pStudents; int m_nGroupID; CStudentCStudent组号:组号:intint m_nGroupIDm_nGroupID学生:学生:CStudentCStudent* * m_pStudentsm_pStudents.CClassCClass设设 置置 学学 生生 :SetStudent(CStudentSetStudent(CStudent*)*)构造空组构造空组nIDnID :CGroup(intCGroup(int nIDnID) ).小组成员小组成员 5 525 25 班级成员班级成员班号:班号:intint m_nClassIDm_nClassID学生:学生:CStudentCStudent* * m_pStudentsm_pStudents.CClassCClass设设 置置 学学 生生 :SetStudent(CStudentSetStudent(CStudent*)*)构造空班构造空班nIDnID :CClass(intCClass(int nIDnID) ).public: void SetStudent(CStudent* pStudents) m_pStudent=pStudent; CGroup(int nID) m_nGroupID=nID; m_pStudents=new CStudnet5; /小组由小组由5名学生组成名学生组成 ;class CClass private: CStudent* m_pStudents; int m_nClassID; public: CClass(int nID) m_nClassID=nID; m_pStudents=new CStudnet35; /班级由班级由35名学生组成名学生组成 CStudent* GetStudent() return m_pStudents; void SetStudent(CStudent* pStudents) m_pStudent=pStudent; ;void main() CStudent theWhole2550= CStudent(Marry), , CStudent(Tom) ; CClass MyClass3(3); /成立班级,但具体由哪些学生组成尚未确定成立班级,但具体由哪些学生组成尚未确定 MyClass3.SetStudent(theWhole+70); /本班学生由学校学生名册中第本班学生由学校学生名册中第71位开始的位开始的35人组成人组成 CGroup Group6(6); Goup6.SetStudent(MyClass3.GetStudent()+25); /第第6学习小组由班级学生名册中第学习小组由班级学生名册中第26名开始的名开始的5个人组成个人组成 class CCompany private: char* m_pName; /按图中要求按图中要求 CPerson* box; /图中标出老板可有可无,故用指针表示图中标出老板可有可无,故用指针表示 CPerson m_Employee20 /公司员工最多公司员工最多20;class CPerson private: char* m_pName; int m_nAge; CCompany* comp; /comp为一个为一个CCompany的数组,因为可为多个公司工作的数组,因为可为多个公司工作 CPeron consort; /按图中的关系添加了这一个属性标明配偶按图中的关系添加了这一个属性标明配偶 int sex; /为标明配偶为男女,所以引入本人的性别为标明配偶为男女,所以引入本人的性别;11.4 11.4 关联关系的实现关联关系的实现同许多面向对象编程语言一样,对关联的实现同许多面向对象编程语言一样,对关联的实现C+没有提供专用语法,编程没有提供专用语法,编程者可以使用指向类的指针、成员对象等语法实现分析设计阶段描述的关联结者可以使用指向类的指针、成员对象等语法实现分析设计阶段描述的关联结构,与实现整体构,与实现整体-部分结构类似,实际上整体部分结构类似,实际上整体-部分结构在部分结构在UML中是以关联特例中是以关联特例的身份出现的。的身份出现的。 公公 司司名称:名称:char* char* m_pNamem_pName老板:老板:CPersonCPerson box box. . .boxbox结婚结婚丈夫丈夫妻子妻子人人姓名姓名:char* char* m_pNamem_pName年龄:年龄:intint m_nAgem_nAge. . .工工作作单单位位由由.掌管掌管0.10.1老板老板为为.工作工作 * 雇佣雇佣11.5 11.5 关于类层次的总结关于类层次的总结11.5.1 认知规律与类层次认知规律与类层次11.5.2 构造函数的一般形式构造函数的一般形式11.5.3 成员函数的特征成员函数的特征(略)(略)
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号