zoukankan      html  css  js  c++  java
  • C++构造函数语义学(二)(基于C++对象模型)

    带有虚函数的情况。

    下面情况编译器也会在需要的时候为其合成。

    1.如果一个类自己声明为虚函数.

     1 #include<iostream>
     2 using namespace std;
     3 class Base
     4 {
     5 public:
     6     virtual void foo(){}
     7 };
     8 int main()
     9 {
    10     Base b;
    11     while (1);
    12     return 0;
    13 }

    分析:由于类中声明了虚函数,所以编译器会为其合成一个出来,这个合成的默认构造函数的作用是用来保存虚函数表的指针。

    2.如果一个类继承了带虚函数的类。

    1)单继承情况

     1 #include<iostream>
     2 using namespace std;
     3 class Base
     4 {
     5 public:
     6     virtual void foo(){}
     7 };
     8 class Deprive:public Base
     9 {
    10 public:
    11     void foo() override {
    12 
    13     }
    14 };
    15 int main()
    16 {
    17     Deprive d;
    18     while (1);
    19     return 0;
    20 }

    分析:由于继承关系,所以类Base的虚函数属性也被Deprive继承下来,由于类Deprive中没有自己的构造函数,所以此时编译器会为其合成一个出来,同样,在这个合成的默认构造函数中,所做的工作是保存虚函数表的指针。(这里通过sizeof(Deprive)可以看出,类的大小还是4。也就是说,类Base和类Deprive共用了一个虚函数表指针).

    2)多继承情况

     1 #include<iostream>
     2 using namespace std;
     3 class Base1
     4 {
     5 public:
     6     virtual void foo1(){}
     7     virtual void foo1(){}
     8 };
     9 class Base2
    10 {
    11 public:
    12     virtual void func1(){}
    13     virtual void func2(){}
    14 };
    15 class Deprive:public Base1,public Base2
    16 {
    17 public:
    18     void foo1() override {}
    19     void func2()override {}
    20     virtual void My_HanShu(){}
    21 };
    22 int main()
    23 {
    24     Deprive d;
    25     while (1);
    26     return 0;
    27 }

    分析:同样,在多继承体系中,编译器会为类Deprive合成一个默认的构造函数出来,用来保存虚函数表的地址,这里通过sizeof(Deprive)可以看出大小为8字节,所以在默认的构造函数中有两个虚函数表指针,一个是与基类共用的,另一个是另外一个基类的。

    注:多继承时,按照继承的顺序,子类的虚函数表指针与第一个继承的父类共用。

    3.类派生自一个继承链串。

     1 #include<iostream>
     2 using namespace std;
     3 class Base1
     4 {
     5 public:
     6     virtual void foo1(){}
     7 };
     8 class Base2:public Base1
     9 {
    10 public:
    11 };
    12 class Deprive:public Base2
    13 {
    14 public:
    15 };
    16 int main()
    17 {
    18     Deprive d;
    19     while (1);
    20     return 0;
    21 }

    分析:这种情况本质没有什么区别,只要基类有虚函数在,那么不管他的派生类的链串有多长,虚函数的属性就会被继承,虚函数属性被继承了,接下来的分析就和前面相同了。

    下面是C++对象模型中的例子(我添加了一些代码以便运行的效果):(书P45页)

     1 #include<iostream>
     2 using namespace std;
     3 class Widget 
     4 {
     5 public:
     6     virtual void flip()=0;
     7 };
     8 void flip(Widget& widget)
     9 {
    10     widget.flip();
    11 }
    12 class Bell:public Widget
    13 {
    14 public:
    15     void flip()
    16     {
    17         cout << "Bell" << endl;
    18     }
    19 };
    20 class Whistle:public Widget
    21 {
    22 public:
    23     void flip()
    24     {
    25         cout << "Whistle" << endl;
    26     }
    27 };
    28 void foo()
    29 {
    30     Bell b;
    31     Whistle w;
    32     flip(b);
    33     flip(w);
    34 }
    35 int main()
    36 {
    37     foo();
    38     while (1);
    39     return 0;
    40 }

     分析:由于编译器在合成的默认构造函数中添加了虚函数表指针,所以接下来在函数void flip(Widget& widget)中的调用是通过虚函数表走的。

    widget.flip()的编译器视角就是:*widget.vptr[1](&widget)  (关于布局写法以后再深谈)。

  • 相关阅读:
    [ERR] Node 10.211.55.8:7001 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
    PAT A1137 Final Grading (25 分)——排序
    PAT A1136 A Delayed Palindrome (20 分)——回文,大整数
    PAT A1134 Vertex Cover (25 分)——图遍历
    PAT A1133 Splitting A Linked List (25 分)——链表
    PAT A1132 Cut Integer (20 分)——数学题
    PAT A1130 Infix Expression (25 分)——中序遍历
    PAT A1142 Maximal Clique (25 分)——图
    PAT A1141 PAT Ranking of Institutions (25 分)——排序,结构体初始化
    PAT A1140 Look-and-say Sequence (20 分)——数学题
  • 原文地址:https://www.cnblogs.com/SunShine-gzw/p/13180910.html
Copyright © 2011-2022 走看看