28、多继承
#include<iostream.h>
class B1
{
public:
B1(int i) { b1 = i; cout<<"Constructor B1"<<endl; }
void Print() { cout<<b1<<endl; }
private:
int b1;
};
class B2
{
public:
B2(int i) { b2 = i; cout<<"Constructor B2"<<endl; }
void Print() { cout<<b2<<endl; }
private:
int b2;
};
class B3
{
public:
B3(int i) { b3 = i; cout<<"Constructor B3"<<endl; }
int Getb3() { return b3; }
private:
int b3;
};
class A:public B2,public B1
{
public:
A(int i,int j,int k,int l);
void Print();
private:
int a;
B3 bb;
};
A::A(int i,int j,int k,int l):B1(i),B2(j),bb(k)
{
a = l;
cout<<"Constructor A."<<endl;
}
void A::Print()
{
B1::Print(); //通过继承的方式
B2::Print();
cout<<a<<bb.Getb3()<<endl; //通过子对象
}
void main()
{
A aa(1,2,3,4);
aa.Print();
}
总结:a.派生类对象调用基类时的顺序与定义时的顺序不同。
b.访问基类的方法有两种:一种是继承,一种是定义子对象。
29、二义性
产生二义性的原因:
1.在多继承的情况下,造成的对基类中某个成员的访问出现的不唯一的情况。如都有相同的函数f();
解决办法:a.区别出是类A或类B的f函数:
c1.A::f(); 或 c1.B::f();
b.在类中定义同名函数f;
2.当一个派生类从多个基类派生,而这些基类又有一个共通过的基类,则对该基类说明的成员进行
访问时,可能会出现二义性;
解决办法:a.区别出事通过类B1或类B2调用类A的a;
c1.B1::a; 或 c1.B2::a;
b.虚基类;
30、虚基类
#include<iostream.h>
class A
{
public:
A(const char *s) { cout<<s<<endl; }
~A() {};
};
class B:virtual public A
{
public:
B(const char *s1,const char *s2):A(s1) { cout<<s2<<endl; }
};
class C:virtual public A
{
public:
C(const char *s1,const char *s2):A(s1) { cout<<s2<<endl; }
};
class D:public B,public C
{
public:
D(const char *s1,const char *s2,const char *s3,const char *s4):B(s4,s2),C(s2,s3),A(s1) { cout<<s4<<endl; }
};
void main()
{
D *dd;
dd = new D("class1","class2","class3","class4");
delete dd;
}
总结:a.在一个成员初始化列表中出现对虚基类和对非虚基类构造函数调用时,虚基类的构造函数先于
非虚基类的构造函数进行;
b.虚基类子对象由最派生类构造函数进行初始化;
c.虚基类子对象只初始化一次;
d.虚基类构造函数先于非虚基类构造函数进行;
初始化:
a.虚基类存在于多个基类时,执行顺序取决于派生类定义时的顺序
b.存在多个子对象时,执行顺序取决于类中声明的顺序
c.常数据(const)成员初始化列表进行初始化
d.静态数据成员 类外初始化
#include<iostream.h>
class B1
{
public:
B1(int i) { b1 = i; cout<<"Constructor B1"<<endl; }
void Print() { cout<<b1<<endl; }
private:
int b1;
};
class B2
{
public:
B2(int i) { b2 = i; cout<<"Constructor B2"<<endl; }
void Print() { cout<<b2<<endl; }
private:
int b2;
};
class B3
{
public:
B3(int i) { b3 = i; cout<<"Constructor B3"<<endl; }
int Getb3() { return b3; }
private:
int b3;
};
class A:public B2,public B1
{
public:
A(int i,int j,int k,int l);
void Print();
private:
int a;
B3 bb;
};
A::A(int i,int j,int k,int l):B1(i),B2(j),bb(k)
{
a = l;
cout<<"Constructor A."<<endl;
}
void A::Print()
{
B1::Print(); //通过继承的方式
B2::Print();
cout<<a<<bb.Getb3()<<endl; //通过子对象
}
void main()
{
A aa(1,2,3,4);
aa.Print();
}
总结:a.派生类对象调用基类时的顺序与定义时的顺序不同。
b.访问基类的方法有两种:一种是继承,一种是定义子对象。
29、二义性
产生二义性的原因:
1.在多继承的情况下,造成的对基类中某个成员的访问出现的不唯一的情况。如都有相同的函数f();
解决办法:a.区别出是类A或类B的f函数:
c1.A::f(); 或 c1.B::f();
b.在类中定义同名函数f;
2.当一个派生类从多个基类派生,而这些基类又有一个共通过的基类,则对该基类说明的成员进行
访问时,可能会出现二义性;
解决办法:a.区别出事通过类B1或类B2调用类A的a;
c1.B1::a; 或 c1.B2::a;
b.虚基类;
30、虚基类
#include<iostream.h>
class A
{
public:
A(const char *s) { cout<<s<<endl; }
~A() {};
};
class B:virtual public A
{
public:
B(const char *s1,const char *s2):A(s1) { cout<<s2<<endl; }
};
class C:virtual public A
{
public:
C(const char *s1,const char *s2):A(s1) { cout<<s2<<endl; }
};
class D:public B,public C
{
public:
D(const char *s1,const char *s2,const char *s3,const char *s4):B(s4,s2),C(s2,s3),A(s1) { cout<<s4<<endl; }
};
void main()
{
D *dd;
dd = new D("class1","class2","class3","class4");
delete dd;
}
总结:a.在一个成员初始化列表中出现对虚基类和对非虚基类构造函数调用时,虚基类的构造函数先于
非虚基类的构造函数进行;
b.虚基类子对象由最派生类构造函数进行初始化;
c.虚基类子对象只初始化一次;
d.虚基类构造函数先于非虚基类构造函数进行;
初始化:
a.虚基类存在于多个基类时,执行顺序取决于派生类定义时的顺序
b.存在多个子对象时,执行顺序取决于类中声明的顺序
c.常数据(const)成员初始化列表进行初始化
d.静态数据成员 类外初始化