C++继承(多继承)之菱形继承与虚函数

一、单继承&多继承&菱形继承

单继承与多继承

单继承:一个子类只有一个直接父类时称这个继承关系为单继承

多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承

在这里插入图片描述
菱形继承
在这里插入图片描述
菱形继承引发的问题:
数据冗余

例: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后,编译器给变量增加了一个特殊的属性

在这里插入图片描述

三、虚函数

类的成员函数前面加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 );
}

在这里插入图片描述
简单理解多态:

1.指向父类调父类,指向子类调子类。

2.构造函数不能为虚函数。

3.最好把父类的析构定义为虚函数,子类将重写父类的虚函数。

4.父类是虚函数,子类不是虚函数,但是子类继承了父类的属性,可以构成多态。

四、纯虚函数
在成员函数的形参后面写上=0,则成员函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。纯虚 函数在派生类中重新定义以后,派生类才能实例化出对象。

class Person
 {
     virtual void Display () = 0;   // 纯虚函数
 protected :
     string _name ;          // 姓名
 };
 
class Student : public Person
 {};

重载、重写、重定义
在这里插入图片描述

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页