Presentation is loading. Please wait.

Presentation is loading. Please wait.

第12讲 多继承与虚基类 多继承 虚基类.

Similar presentations


Presentation on theme: "第12讲 多继承与虚基类 多继承 虚基类."— Presentation transcript:

1 第12讲 多继承与虚基类 多继承 虚基类

2 学习目标 理解多继承的相关概念; 掌握多继承派生类的构造函数 掌握虚基类的相关概念和定义方法 理解虚基类构造函数的定义方法

3 多继承 可以用多个基类来派生一个类。 D 多继承是单继承的扩展 A B C 派生类中新定义的成员

4 声明多重继承的方法 class 派生类名 : [继承方式]基类名1 , [继承方式]基类名2, ...,[继承方式]基 类名n { 派生类成员声明; };

5 class 类名:<Access>类名1,..., <Access>类名n {
例如: class 类名:<Access>类名1,..., <Access>类名n { private: ; //私有成员说明; public: ; //公有成员说明; protected: ; //保护的成员说明; }; 继承方式 class D: public A, protected B, private C { //派生类中新增加成员 }; 第一章 VC集成开发环境

6 class A { public: displayA() { cout<<a; } private: int a; }; class B { public: displayB() { cout<<b; } private: int b; class C:public A,public B { public: displayC() { cout<<c; } private: int c;

7 多继承结构 A int a; void DisplayA( ); B int b; void DisplayB( ); C int a;
int c; void DisplayA( ); void DisplayB( ); void DisplayC( );

8 B b1(10,20); b1.ShowB(); class A{ int x1,y1;
public: A(int a,int b) { x1=a; y1=b; } void ShowA(void){ cout<<"A.x="<<x1<<'\t'<<"A.y="<<y1<<endl; } }; class B{int x2,y2; public: B(int a,int b) {x2=a; y2=b; } void ShowB(void){ cout<<"B.x="<<x2<<'\t'<<"B.y="<<y2<<endl; } class C:public A,private B{ int x,y; public: C(int a,int b,int c,int d,int e,int f):A(a,b),B(c,d) {x=e; y=f; } void ShowC(void){cout<<"C.x="<<x<<'\t'<<"C.y="<<y<<endl; ShowA();ShowB(); } void main(void) { C c(1,2,3,4,5,6); c.ShowC(); c.ShowA (); c.ShowB (); } 公有派生 私有派生 仍为公有 成为私有 B b1(10,20); b1.ShowB(); 非法,私有类外不可调用 第一章 VC集成开发环境

9 多继承派生类的构造函数 派生类构造函数的调用顺序如下: 基类的构造函数 基类子对象的构造函数 派生类的构造函数
多继承下的构造函数和析构函数与单继承下的构造函数和析构函数是相似的,派生类的构造函数需要对基类成员、内嵌子对象和新增成员进行初始化。 构造函数不能被继承,派生类的构造函数必须调用基类的构造函数来初始化基类成员和基类子对象。 派生类构造函数的调用顺序如下: 基类的构造函数 基类子对象的构造函数 派生类的构造函数

10 { public: A(int aa=0) { a=aa; } private: int a; }; class B
class A { public: A(int aa=0) { a=aa; } private: int a; }; class B { public: B(int bb=0) { b=bb; } private: int b; class C:public A,public B { public:C(int a1,int a2,int b1,int b2,int cc):A(a1), B(b1), a(a2), b(b2){ c=cc; } private: A a; B b; int c; 构造函数 10

11 基类子对象举例 class Derived: public Base2, public Base1{ int z; Base1 b1,b2;
Derived(int a,int b):Base1(a),Base2(20), b1(200),b2(a+b) {z=b; cout<<"调用派生类的构造函数!\n";} ~Derived( ){cout<<"调用派生类的析构函数!\n";} }; void main(void) { Derived c(100,200); } 基类子对象 基类子对象构造 基类成员构造 基类成员构造用基类名, 基类子对象构造用对象名

12 当撤销派生类对象时,析构函数的调用正好相反。
class B:public A{ int y; A a1; public: B(int a, int b):A(a),a1(3){y=b;} }; 基类的构造函数 基类子对象的构造函数 派生类的构造函数 当撤销派生类对象时,析构函数的调用正好相反。 第一章 VC集成开发环境

13 public: Base1(int a){ x=a;cout<<"调用基类1的构造函数!\n"; }
class Base1 { int x; public: Base1(int a){ x=a;cout<<"调用基类1的构造函数!\n"; } ~Base1( ){ cout<<"调用基类1的析构函数!\n"; } }; class Base2 { int y; public: Base2(int a){ y=a;cout<<"调用基类2的构造函数!\n"; } ~Base2( ){ cout<<"调用基类2的析构函数!\n"; } class Derived:public Base2, public Base1{ int z; public: Derived(int a,int b):Base1(a),Base2(20) {z=b; cout<<"调用派生类的构造函数!\n";} ~Derived( ){cout<<"调用派生类的析构函数!\n";} void main(void) { Derived c(100,200); } 先说明基类2 调用基类2的构造函数 调用基类1的构造函数 调用派生类的构造函数 调用派生类的析构函数 调用基类1的析构函数 调用基类2的析构函数 第一章 VC集成开发环境

14 public: Base1(int a) {x=a;cout<<"调用基类1的构造函数!\n";}
class Base1 { int x; public: Base1(int a) {x=a;cout<<"调用基类1的构造函数!\n";} ~Base1( ) {cout<<"调用基类1的析构函数!\n";} }; class Base2 { int y; public: Base2(int a) {y=a;cout<<"调用基类2的构造函数!\n";} ~Base2( ){cout<<"调用基类2的析构函数!\n";} class Derived:public Base2, public Base1{ int z; Base1 b1,b2; public: Derived(int a,int b):Base1(a),Base2(20), b1(200),b2(a+b) {z=b; cout<<"调用派生类的构造函数!\n";} ~Derived( ){cout<<"调用派生类的析构函数!\n";} void main(void) { Derived c(100,200); } 第一章 VC集成开发环境

15 运行结果 调用基类2的构造函数 说明基类1的对象b1,b2 调用基类1的构造函数 调用基类1的构造函数 调用基类1的构造函数
调用派生类的构造函数 调用派生类的析构函数 调用基类1的析构函数 调用基类1的析构函数 调用基类1的析构函数 调用基类2的析构函数

16 { public: B1(int i) { cout<<"B1 "<<i<<endl; } };
class B1 { public: B1(int i) { cout<<"B1 "<<i<<endl; } }; class B2 { public: B2(int j) { cout<<"B2 "<<j<<endl; } }; class B3 { public: B3( ) { cout<<"B3 *"<<endl; } }; class C:public B2,public B1,public B3 {public: C(int a,int b,int c,int d):B1(a),memB2(d),memB1(c),B2(b){ } private: B1 memB1; B2 memB2; B3 memB3; }; void main() { C obj(1,2,3,4); } 16

17 多继承引起的二义性问题 class A { public: void display() { cout<<"A"<<endl; } }; class B { public: void display() { cout<<"B"<<endl; } class C: public A, public B { }; void main() { C c; c.display(); }

18 多继承引起的二义性问题 A void display(); B C void A::display();
void B::display(); C c; c.A::display(); c.B::display(); C c; c.display();

19 v.x=5; v. A::x=5; 多继承引起的二义性问题 public D v; 派生类对象 D A x A() B B() 产生了冲突
用类作用符限定

20 这时,可以利用类作用域符::来指明数据或函数的来源。
class A{ public: int x; void Show(){cout <<"x="<<x<<'\n';} A(int a=0){x=a;} }; class B{ B(int a=0){x=a;} class C:public A,public B{ int y; public: void Setx(int a){ x=a;} //c1对象中有两个x成员 void Sety(int b){y=b;} int Gety() {return y;} void main(void) { C c1; c1.Show(); //c1对象中有两个Show()函数 } 这时,可以利用类作用域符::来指明数据或函数的来源。 如:A::x=a; c1.B::Show();

21 第11讲 类的继承(二) 多继承 虚基类

22 虚基类 x A() y B() x A() z C() x A() dx D() x A() z C() y B() 类B 是类A的派生类
类C 是类A的派生类 B类 类D 是类B和类C的派生类 这样,类D中就有两份类A的拷贝 类A拷贝 x A() y B() x A() z C() C类 x A() A类 D类 B类 C类

23 虚基类 这种同一个公共的基类在派生类中产生多个拷贝,不仅多占用了存储空间,而且可能会造成多个拷贝中的数据不一致和模糊的引用。 D d;
dx D() x A() z C() y B() 这种同一个公共的基类在派生类中产生多个拷贝,不仅多占用了存储空间,而且可能会造成多个拷贝中的数据不一致和模糊的引用。 类A拷贝 B类 类A拷贝 C类 D d; d.x=10; //模糊引用 D类

24 例子 x A() y B() x A() z C() 模糊引用,错误! dx D() class A{ public: int x;
A(int a=0) { x=a;} }; class B:public A{ public: int y; B(int a=0,int b=0):A(a) { y=b;} class C:public A{ public: int z; C(int a,int c):A(a){ z=c; } class D:public B,public C{ public: int dx; D(int a1,int b,int c,int d,int a2):B(a1,b),C(a2,c) { dx=d;} void main(void) { D d1(10,20,30,40,50); cout<<d1.x<<endl; } A() y b=20 B() x a2=50 A() z c=30 C() 模糊引用,错误! dx dx=40 D() D类

25 虚基类 在多继承中,若使公共基类在派生类中只有一个拷贝,则可将这种基类说明为虚基类。虚基类的作用:可以使得在继承间接共同基类时只保留一份成员。 在派生类的定义中,只要在基类的类名前加上关键字virtual,就可以将基类说明为虚基类。 class B:public virtual A{ public: int y; B(int a=0, int b=0 ):A(b) { y=a;} }; 25

26 void display( ) { cout<<a<<endl; } };
class A{ public: int a; void display( ) { cout<<a<<endl; } }; class B:virtual public A { }; class C:virtual public A { }; class D:virtual public A { }; class E:public B,public C,public D{ }; void main( ) { E e; e.a=1; e.display(); } 为了保证虚基类的成员在派生类中只继承一次,应当在该基类的所有直接派生类中声明为虚基类。 26

27 一份拷贝,在D( )的构造函数中直接调用A()
x A() x A() y B() x A() z C() x A() y B() z C() dx D() 由虚基类派生出的对象初始化时,直接调用虚基类的构造函数。因此,若将一个类定义为虚基类,则一定有正确的构造函数可供所有派生类调用。 A类 B类 C类 D类 第一章 VC集成开发环境

28 虚基类的构造函数 如果在虚基类中定义了带参数的构造 函数,且没有默认构造函数,则在其 所有直接或间接派生类中,都必须通 过初始化表对虚基类进行初始化。

29 class A {public: A(int aa) { a=aa; } private: int a; }; class B:virtual public A {public: B(int aa,int bb):A(aa) { b=bb; } private: int b; class C:virtual public A {public: C(int aa,int cc):A(aa) { c=cc; } private: int c; class D:public B,public C {public: D(int aa,int bb,int cc,int dd):A(aa),B(aa,bb),C(aa,cc) { d=dd; } private: int d;

30 没有对虚基类构造函数的调用,用缺省的构造函数
class A{ public: int x; A(int a=0) { x=a;} }; class B:public virtual A{ public: int y; B(int a=0,int b=0): A(a) {y=b;} class C:public virtual A{ public: int z; C(int a=0,int c=0):A(a){z=c; } class D:public B,public C{ public: int dx; D(int a1,int b,int c,int d,int a2):B(a1,b),C(a2,c) {dx=d;} void main(void) { D d1(10,20,30,40,50); cout<<d1.x<<endl; d1.x=400; cout<<d1.y<<endl; } 400 20 50 400 20 直接在派生类中调用虚基类的构造函数 , A(a2) 没有对虚基类构造函数的调用,用缺省的构造函数

31 第12讲 多继承与虚基类 多继承 虚基类


Download ppt "第12讲 多继承与虚基类 多继承 虚基类."

Similar presentations


Ads by Google