177继承性和派生类_继承中的二义性
178继承性和派生类_例10_12
179继承性和派生类_虚基类
180继承性和派生类_虚基类实例1
181继承性和派生类_虚基类实例2
10.3.3 多继承中的二义性1. 多继承中派生类对基类成员访问在下列两种情况下可能出现二义性。
(1) 访问不同基类的相同成员时可能出现二义性
例如,C类有两个直接基类A类和B类,其中,A类和B类中都有一个公有成员函数f( ),并且C类公有继承A和B,这时当C类的对象c1,访问基类成员f( )时,c1.f( )则会出现二义性。
class A
{
public:
void f();
};
class B
{
public:
void f();
void g();
};
class C:public A,public B
{
public:
void g();
void h();
};(2) 访问共同基类的成员时可能出现二义性
例如,当一个派生类有多个基类,而这些基类中又有一个共同的基类,这时候对这个共同的基类中成员的访问可能出现二义性。
class A
{
public:
int a;
};
class B1:public A
{
private:
int b1;
};
class B2:public A
{
private:
int b2;
};
class C:public B1,public B2
{
public:
int f()
{
return B1::a+B2::a;
}
private:
int b3;
};
例10.12
#include
class A
{
public:
A(int i) { a=i; cout<void print() { cout<~A() {cout<private:
int a;
};
class B1:public A
{
public:
B1(int i,int j):A(i) { b1=j; cout<void print() { A::print(); cout<~B1() { cout<private:
int b1;
};
class B2:public A
{
public:
B2(int i,int j):A(i) { b2=j; cout<void print() { A::print(); cout<~B2() { cout<private:
int b2;};
class C:public B1,public B2
{
public:
C(int i,int j,int k,int l,int m):B1(i,j),B2(k,l),c(m)
{ cout<void print()
{
B1::print();
B2::print();
cout<}
~C() { cout<private:
int c;
};
void main()
{
C c1(1,2,3,4,5);
c1.print();
}
派生类C的对象初始化的时候要两次调用共同间接基类A的构造函数,对类A中的数据成员也要进行两次初始化。10.4 虚基类
10.4.1虚基类的概念
在前面讲过的具有公共基类的例子中,当创建一个C类的对象时要两次调用A类的构造函数,如果只想调用一次A类构造函数时,则须在A类作为B1、B2类基类时将其定义为虚基类。
定义虚基类的方法如下:
class B1:virtual public A
{…}
class B2:virtual public A
{…}
定义为虚基类后也可以避免二义性。当定义虚基类后,A,B1,B2和C类之间的关系如下:
class A
{
public:
int a;
};
class B1: virtual public A
{
private:
int b1;
};
class B2: virtual public A
{
private:
int b2;
};
class C:public B1,public B2
{
public:
int f()
{
return a;
}
private:
int b3;
};10.4.2 含有虚基类的派生类的构造函数
具有虚基类的派生类的构造函数中不仅包含两个直接基类的构造函数,另外还包含虚基类A的构造函数,并且规定虚基类A的构造函数优先调用,只调用一次,在B1类和B2类的构造函数中不再调用A类的构造函数。
#include
class A
{
public:
A(const char *s) { cout<~A() {}
};
class B:virtual public A
{
public:
B(const char *s1,const char *s2):A(s1)
{cout<};
class C:virtual public A
{
public:
C(const char *s1,const char *s2):A(s1)
{ cout<};
class D:public B,public C
{public:
D(const char *s1,const char *s2,const char *s3,const char *s4)
:B(s1,s2),C(s1,s3),A(s1)
{
cout<};
void main()
{D *ptr=
new D("class A","class B","class C","class D");
delete ptr;
}1.在整个继承结构中,直接或间接继承虚基类的所有派生类都必须在构造函数初始化表中给出对虚基类的构造函数的调用,如果未列出,则表示调用虚基类的缺省构造函数,来初始化派生类对象中的子对象。
2.规定只在建立对象的最远派生类类的构造函数中调用虚基类的构造函数,而该派生类的基类构造函数中忽略对虚基类构造函数的调用,这样就保证了对象虚基类的子对象只初始化化一次。应用举例
#include
#include
#include
typedef char string80[80];
class Date
{public:
Date() {}
Date(int y,int m,int d) { SetDate(y,m,d);}
void SetDate(int y,int m,int d)
{ Year=y;
Month=m;
Day=d;
}
void GetStringDate(string80 &Date)
{ sprintf(Date,"%d/%d/%d",Year,Month,Day);
}
protected:
int Year,Month,Day;//年月日
};
class Time
{public:
Time() {}
Time(int h,int m,int s) { SetTime(h,m,s);}
void SetTime(int h,int m,int s)
{ Hours=h;
Minutes=m;
Seconds=s;
}
void GetStringTime(string80 &Time)
{ sprintf(Time,"%d:%d:%d",Hours,Minutes,Seconds);
}
protected:
int Hours,Minutes,Seconds;
};
class TimeDate:public Date,public Time
{
public:
TimeDate():Date() {}
TimeDate(int y,int mo,int d,int h,int mi,int s):
Date(y,mo,d),Time(h,mi,s)
{}
void GetStringDT(string80 &DTstr)
{sprintf(DTstr,"%d/%d/%d;%d:%d:%d",Year,Month,Day,Hours,Minutes,Seconds);
} };
void main()
{TimeDate date1,date2(1998,8,12,12,45,10);
string80 DemoStr;
date1.SetDate(1998,8,7);
date1.SetTime(10,30,45);
date1.GetStringDT(DemoStr);
cout<date1.GetStringDate(DemoStr);
cout<date1.GetStringTime(DemoStr);
cout<date2.GetStringDT(DemoStr);
cout<}