多继承可以看作是单继承的扩展。所谓多继承是指派生类具有多个基类,派生类与每个基类之间的关系仍可看作是一个单继承。
多继承下派生类的定义格式如下:
class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…
{
<派生类类体>
};
其中,<继承方式1>,<继承方式2>,…是三种继承方式:public、private、protected之一。例如:
class A
{
…
};
class B
{
…
};
class C : public A, public B
{
…
};
其中,派生类C具有两个基类(类A和类B),因此,类C是多继承的。按照继承的规定,派生类C的成员包含了基类A, B中成员以及该类本身的成员。
多继承的构造函数
在多继承的情况下,派生类的构造函数格式如下:
<派生类名>(<总参数表>):<基类名1>(<参数表1>),<基类名2>(<参数表2>),…
<子对象名>(<参数表n+1>),…
{
<派生类构造函数体>
}
其中,<总参数表>中各个参数包含了其后的各个分参数表。
多继承下派生类的构造函数与单继承下派生类构造函数相似,它必须同时负责该派生类所有基类构造函数的调用。同时,派生类的参数个数必须包含完成所有基类初始化所需的参数个数。
派生类构造函数执行顺序是先执行所属基类的构造函数,再执行派生类本身构造函数,处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的各基类顺序,与派生类构造函数中所定义的成员初始化列表的各项顺序无关。也就是说,执行基类构造函数的顺序取决于定义派生类时基类的顺序。可见,派生类构造函数的成员初始化列表中各项顺序可以任意地排列。
下面通过一个例子来说明派生类构造函数的构成及其执行顺序。
#include <iostream.h>
class B1
{
public:
B1(int i)
{
b1 = i;
cout<<"构造函数 B1."<<i<< endl;
}
void print()
{
cout<<"B1.print()"<<b1<<endl;
}
private:
int b1;
};
class B2
{
public:
B2(int i)
{
b2 = i;
cout<<"构造函数 B2."<<i<< endl;
}
void print()
{
cout<<"B2.print()"<<b2<<endl;
}
private:
int b2;
};
class B3
{
public:
B3(int i)
{
b3 = i;
cout<<"构造函数 B3."<<i<<endl;
}
int getb3()
{
return b3;
}
private:
int b3;
};
class A : public B2, public B1
{
public:
A(int i, int j, int k, int l):B1(i), B2(j), bb(k)
{
a = l;
cout<<"构造函数 A."<<a<<endl;
}
void print()
{
B1::print();
B2::print();
cout<<"A.print()"<<a<<","<<bb.getb3()<<endl;
}
private:
int a;
B3 bb;
};
void main()
{
A aa(1, 2, 3, 4);
aa.print();
}
该程序的输出结果为:
构造函数 B2.2
构造函数 B1.1
构造函数 B3.3
构造函数 A.4
B1.print().1
B2.print()2
A.print()4, 3
在该程序中,作用域运算符::用于解决作用域冲突的问题。在派生类A中的print()函数的定义中,使用了B1::print;和B2::print();语句分别指明调用哪一个类中的print()函数,这种用法应该学会。