多继承
一个子类有两个或以上直接父类时称这个继承关系为多继承,多继承可以看做是单继承的一种扩展。所谓多继承是指派生类具有多个基类,派生类与每个基类之间的关系仍可看做是一个单继承。
多继承的格式如下:
class A
{
};
class B
{
};
class C :public A, public B
{
};
其中,派生类C具有两个基类(A和B),所以C的成员包含A和B中的成员以及该类本身的成员。
多继承的构造函数
在多继承的情况下,派生类的构造函数执行顺序是先执行所属基类的构造函数,在执行派生类本身构造函数,处于同一层次的各构造函数的执行顺序取决于定义派生类时所指定的各基类顺序,与派生类构造函数中所定义的成员初始化列表的各项顺序无关。
代码实现
class A
{
public:
A(int x) :
a(x)
{
cout << "A()" << endl;
}
void print()
{
cout << a << endl;
}
private:
int a;
};
class B
{
public:
B(int x) :
b(x)
{
cout << "B()" << endl;
}
void print()
{
cout << b << endl;
}
private:
int b;
};
class C:public A,public B
{
public:
C(int x,int y,int z):
A(y),
B(x),
c(z)
{
cout << "C()" << endl;
}
void print()
{
A::print();
B::print();
cout << c << endl;
}
private:
int c;
};
void FunTest()
{
C c(1,2,3);
c.print();
}
int main()
{
FunTest();
return 0;
}
输出为:
派成员访问的二义性
在派生类中对基类成员的访问应该是唯一的,但是由于是多继承的情况,所以有时可能会出现对基类中的某个成员的访问出现不唯一的情况,这就是对基类成员访问的二义性。
具体来说就是当派生类所继承的两个或者多个基类中出现了同名的成员时,派生类对其的访问就出现了二义性。解决这个问题的方法就是通过作用域运算符进行限定。就如上面的代码中两个基类中同时出现了 “print()”函数,如果不在调用函数前加上作用域限定符,程序在编译时并不会出错,但是运行中会出现崩溃。
去掉作用域限定符后结果如图
菱形继承
继承关系形如菱形的继承称作菱形继承。
如图所示:
代码形式
class A
{
public:
A()
{}
};
class B:public A
{
public:
B()
{}
};
class C:public A
{
public:
C()
{}
};
class D:public B,public C
{
public:
D()
{}
};
在菱形继承中存在着一些问题,在派生类D的对象中我们可以了解到其中会出现数据的冗余,一些数据只需保存一份,却在派生类D的对象中保存了两份。
例如下代码
class Person
{
public:
Person()
{}
protected:
string _name;
};
class Student:public Person
{
public:
Student()
{}
protected:
int _id;
};
class Teacher:public Person
{
public:
Teacher()
{}
protected:
int c;
};
class Course:public Student,public Teacher
{
public:
Course()
{}
protected:
string _majorCourse;
};
此时Course类的对象的模型如图所示:
此时可能用户只需要类中teacher或者student的成员数据,但是在对象中把这两份都储存了,出现数据的冗余。