C++继承之菱形继承与虚函数

左手的ㄟ右手 2022-05-26 13:20 339阅读 0赞

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

单继承与多继承

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

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

20180503122806821![Image 1][]

菱形继承

20180503122823123![Image 1][]

菱形继承引发的问题:

数据冗余

例:B、C中的_a都是来自于A,其实两个_a是同一个,但是因为B、C各自继承,产生了两份,造成了数据冗余

二义性

例:由于D继承于B、C,B、C继承于A,所以D中的_a不知道是来自B还是来自C,于是产生了二义性。

二、虚继承-———解决菱形继承的数据冗余与二义性

将B和C的继承变为虚继承:

  1. class B:virtual public A
  2. class C:virtual public A

不过虚继承只能解决这种有公有继承祖先的多继承,菱形继承,比如下面这个例子加上virtual就无法解决

  1. class A1
  2. {
  3. public:
  4. int a;
  5. };
  6. class A2
  7. {
  8. public:
  9. int a;
  10. };
  11. class B :virtual public A1, virtual public A2
  12. {
  13. public:
  14. };
  15. int main()
  16. {
  17. B b1;
  18. b1.a;//编译出错,访问不明确
  19. system("pause");
  20. return 0;
  21. }

这样我们只能自己解决,加上域限制符:

  1. int main()
  2. {
  3. B b1;
  4. b1.A1::a=100;
  5. b1.A2::a=200;
  6. system("pause");
  7. return 0;
  8. }

问题: 在菱形继承中加上virtual和不加virtual的父类大小有区别吗?

  1. class A
  2. {
  3. public:
  4. int z;
  5. };
  6. class base1:virtual public A//加上virtual
  7. {
  8. public:
  9. int a;
  10. };
  11. class base2:public A//没有加virtual
  12. {
  13. public:
  14. int b;
  15. };
  16. class stu:public base1,public base2
  17. {
  18. public:
  19. int c;
  20. };
  21. int main()
  22. {
  23. cout << sizeof(A) << endl;
  24. cout << sizeof(base1) << endl;//加上virtual
  25. cout << sizeof(base2) << endl;//没有加virtual
  26. system("pause");
  27. return 0;
  28. }
  29. //结果为:4 12 8

由此分析:加上virtual后,编译器给变量增加了一个特殊的属性

20180503122953658

2018050312301215![Image 1][]

![Image 1][]

三、虚函数

类的成员函数前面加virtual关键字,则这个成员函数称为虚函数。

虚函数重写:当在子类的定义了一个与父类完全相同的虚函数时,则称子类的这个函数重写(也称覆盖)了父类的这个虚函数。

重写只发生在父类与子类之间。

  1. 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][]201805031231203

简单理解多态:

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

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

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

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

四、纯虚函数

  1. 在成员函数的形参后面写上=0,则成员函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。纯虚 函数在派生类中重新定义以后,派生类才能实例化出对象。
  1. class Person
  2. {
  3. virtual void Display () = 0; // 纯虚函数
  4. protected :
  5. string _name ; // 姓名
  6. };
  7. class Student : public Person
  8. {};

重载、重写、重定义

20180503123156890

![Image 1][]

[Image 1]:

发表评论

表情:
评论列表 (有 0 条评论,339人围观)

还没有评论,来说两句吧...

相关阅读

    相关 C++:53---菱形继承继承

    一、菱形继承 在介绍虚继承之前介绍一下菱形继承 概念:A作为基类,B和C都继承与A。最后一个类D又继承于B和C,这样形式的继承称为菱形继承 菱形继承的缺