请教一下C++类的继承(虚继承和多继承)导致Class内存变化的问题

发布于 2022-09-06 00:10:42 字数 2190 浏览 29 评论 0

请教一下C++类的继承(虚继承和多继承)导致内存变化的问题:

class Class_Base
    {
    private:
        int base_data;
    public:
        void f1() {cout << "\nLet's find the mean.\n";}
        void f2() {cout << "\nLet's find the median.\n";}
        virtual void f3() {cout << "\nLet's find the mode.\n";}
    };

class Class_E: virtual/public Class_Base
    {
    private:
        int derived_data1;
    public:
        void f4() {cout << "\nLet's find the variance.\n";}
        void f5() {cout << "\nLet's find the deviation.\n";}
    };
class Class_F: virtual/public Class_Base
    {
    private:
        int derived_data2;
    public:
        void f4() {cout << "\nLet's find the variance.\n";}
        virtual void f6() {cout << "\nLet's find the standard deviation.\n";}
    };

class Class_GG: public Class_E, public Class_F
    {
    public:
        void functions()
            {
            Class_E :: f4();
            f5();
            Class_F :: f4();
            f6();
            }
    };

int main()
    {
    printf("\nThe size of the base class is %d.", sizeof(Class_Base));
    printf("\nThe size of the 1st derived class is %d.", sizeof(Class_E));
    printf("\nThe size of the 2nd derived class is %d.", sizeof(Class_F));
    printf("\nThe size of the derived-derived class is %d.", sizeof(Class_GG));
    return 0;
    }

经过我的实验,

  1. 如果Base所有函数都是void(包括f3)没有virtual,那么派生Class_E的大小是8。
  2. 如果只要有一个Base函数(比如f3)是virtual,或者派生Class_E的继承本身是virtual,那么派生Class_E的大小是16。
  3. 如果既有Base虚函数(比如f3)、又有虚继承,那么派生Class_E的大小是32。
    所以,请问:为什么是8、16、32这样的大小呢?

另外,如果Class_E和Class_F从Class_Base派生时都是虚继承virtual而不是public继承,那么在Class_GG里,本来应该可以避免Class_E和Class_F都有一个叫f4()的函数的命名冲突。但是我又试了一下,先把Class_E和Class_F都改成从Class_Base的虚继承,再在Class_GG里这样写

class Class_GG: Class_E, Class_F // 或者public Class_E, public Class_F // 或者virtual Class_E, vitual Class_F
    {
    public:
        void functions()
            {
            f4();
            f5();
            f6();
            }
    };

然而编译时却无法通过。请问:到底应该怎么解决这种多继承里函数命名的冲突呢? functions()到底又是什么呢?

谢谢!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

戏蝶舞 2022-09-13 00:10:42

如果了解了C++内存对象模型,就可以解释这些行为。
主要有两点:virtual函数依靠vptr,在运行时确定实际函数;virtual继承的积累在整个继承体系中共享一个积累对象。

以下根据Linux中使用g++编译器实现的内存模型进行分析。

  1. 如果Base所有函数都是void(包括f3)没有virtual,那么派生Class_E的大小是8。

    Class_E类的内存对象模型如下:
    +-----------------------+ 0
    | base_data(4 bytes)    |
    +-----------------------+ 4
    | derived_data1(4 bytes)|
    +-----------------------+ 8
    
  2. 如果只要有一个Base函数(比如f3)是virtual,那么派生Class_E的大小是16。

    Class_E类的内存对象模型如下:
    +-----------------------+ 0
    | vptr(8 bytes)         |
    +-----------------------+ 8
    | base_data(4 bytes)    |
    +-----------------------+ 12
    | derived_data1(4 bytes)|
    +-----------------------+ 16
    
  3. 如果派生Class_E的继承本身是virtual,那么派生Class_E的大小是16。

    Class_E类的内存对象模型如下:
    +-----------------------+ 0
    | vptr(8 bytes)         |
    +-----------------------+ 8
    | derived_data1(4 bytes)|
    +-----------------------+ 12
    | base_data1(4 bytes)   |
    +-----------------------+ 16
    

4.如果既有Base虚函数(比如f3)、又有虚继承,那么派生Class_E的大小是32。

Class_E类的内存对象模型如下:
+-----------------------+ 0
| vptr(8 bytes)         |
+-----------------------+ 8
| derived_data1(4 bytes)|
+-----------------------+
| padding(4 bytes)      |
+-----------------------+ 16
| Base vptr(8 bytes)    |
+-----------------------+ 24
| base_data1(4 bytes)   |
+-----------------------+ 
| padding(4 bytes)      |
+-----------------------+ 32
  1. Class_E和Class_F中有同样的函数f4,由于是不同的两个基类,没有办法通过虚拟继承解决冲突,只有明确cast到对应的类型才可以确定具体调用哪个函数。

参考:《深度探索C++内存对象模型》

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文