C++继承之菱形继承与虚函数
一、单继承&多继承&菱形继承
单继承与多继承
单继承:一个子类只有一个直接父类时称这个继承关系为单继承
多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承
![Image 1][]
菱形继承
![Image 1][]
菱形继承引发的问题:
数据冗余
例:B、C中的_a都是来自于A,其实两个_a是同一个,但是因为B、C各自继承,产生了两份,造成了数据冗余
二义性
例:由于D继承于B、C,B、C继承于A,所以D中的_a不知道是来自B还是来自C,于是产生了二义性。
二、虚继承-———解决菱形继承的数据冗余与二义性
将B和C的继承变为虚继承:
class B:virtual public A
class C:virtual public A
不过虚继承只能解决这种有公有继承祖先的多继承,菱形继承,比如下面这个例子加上virtual就无法解决
class A1
{
public:
int a;
};
class A2
{
public:
int a;
};
class B :virtual public A1, virtual public A2
{
public:
};
int main()
{
B b1;
b1.a;//编译出错,访问不明确
system("pause");
return 0;
}
这样我们只能自己解决,加上域限制符:
int main()
{
B b1;
b1.A1::a=100;
b1.A2::a=200;
system("pause");
return 0;
}
问题: 在菱形继承中加上virtual和不加virtual的父类大小有区别吗?
class A
{
public:
int z;
};
class base1:virtual public A//加上virtual
{
public:
int a;
};
class base2:public A//没有加virtual
{
public:
int b;
};
class stu:public base1,public base2
{
public:
int c;
};
int main()
{
cout << sizeof(A) << endl;
cout << sizeof(base1) << endl;//加上virtual
cout << sizeof(base2) << endl;//没有加virtual
system("pause");
return 0;
}
//结果为:4 12 8
由此分析:加上virtual后,编译器给变量增加了一个特殊的属性
![Image 1][]
![Image 1][]
三、虚函数
类的成员函数前面加virtual关键字,则这个成员函数称为虚函数。
虚函数重写:当在子类的定义了一个与父类完全相同的虚函数时,则称子类的这个函数重写(也称覆盖)了父类的这个虚函数。
重写只发生在父类与子类之间。
class Person { public : virtual void BuyTickets() { cout<<" 买票"<< endl; } protected : string _name ; // 姓名 }; class Student : public Person { public : virtual void BuyTickets() { cout<<" 买票-半价 "<<endl ; } protected : int _num ; //学号 }; //void Fun(Person* p) void Fun (Person& p) { p.BuyTickets (); } void Test () { Person p ; Student s ; Fun(p ); Fun(s ); }
![Image 1][]
简单理解多态:
1.指向父类调父类,指向子类调子类。
2.构造函数不能为虚函数。
3.最好把父类的析构定义为虚函数,子类将重写父类的虚函数。
4.父类是虚函数,子类不是虚函数,但是子类继承了父类的属性,可以构成多态。
四、纯虚函数
在成员函数的形参后面写上=0,则成员函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。纯虚 函数在派生类中重新定义以后,派生类才能实例化出对象。
class Person
{
virtual void Display () = 0; // 纯虚函数
protected :
string _name ; // 姓名
};
class Student : public Person
{};
重载、重写、重定义
![Image 1][]
[Image 1]:
还没有评论,来说两句吧...