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)  (关于布局写法以后再深谈)。

  • 相关阅读:
    切割窗口url
    软键盘弹出底部被顶上去
    C语言字符串处理标准库函数的源码(转)
    slapd配置文件详述
    OPENLDAP安装配置方法
    const成员函数
    OPENLDAP概述
    当前比较有名的Xml数据库
    『转』使用 Scalable Vector Graphics 为 ASP.NET 构建基于 XML 的灵活、轻量的图像
    SqlCommand_ExecuteNonQuery 方法返回值为1的解释
  • 原文地址:https://www.cnblogs.com/SunShine-gzw/p/13180910.html
Copyright © 2011-2022 走看看