虚函数/继承/虚继承下的内存图

虚函数

  • 概念:虚函数,是指被virtual关键字修饰的成员函数。

  • 作用:函数作为多态的实现方式,重要性毋庸置疑。多态意指相同的消息给予不同的对象会引发不同的动作(一个接口,多种方法)

  • 虚函数的内存模型虚函数Virtual Function)是通过虚函数表(Virtual Table,简称为V-Table)来实现的。虚函数表主要存储的是指向一个类的虚函数地址的指针,通过使用虚函数表,继承、覆盖的问题都都得到了解决。

    • 单继承无虚函数覆盖的情况
    #include <iostream>
    #include <string>
    class Base{
      public:
        virtual void f(){
            std::cout << "Base::f()" << std::endl;
        }
        virtual void g(){
            std::cout << "Base::g()" << std::endl;
        }
        virtual void h(){
            std::cout << "Base::h()" << std::endl;
        }
    };
    
    class Derived : public Base{
    public:
        virtual void f1(){
            std::cout << "Derived::f1()" << std::endl;
        }
        virtual void g1(){
            std::cout << "Derived::g1()" << std::endl;
        }
    
        virtual void h1(){
            std::cout << "Derived::h1()" << std::endl;
        }
    };
     

    虚函数表: 图片

    • 单继承有虚函数覆盖的情况
    #include <iostream>
    #include <string>
    class Base{
      public:
        virtual void f(){
            std::cout << "Base::f()" << std::endl;
        }
        virtual void g(){
            std::cout << "Base::g()" << std::endl;
        }
        virtual void h(){
            std::cout << "Base::h()" << std::endl;
        }
    };
    
    class Derived : public Base{
    public:
        virtual void f1(){
            std::cout << "Derived::f1()" << std::endl;
        }
        virtual void g(){
            std::cout << "Derived::g1()" << std::endl;
        }
    
        virtual void h1(){
            std::cout << "Derived::h1()" << std::endl;
        }
    };
     

    虚函数表: 图片

    • 多重继承的情况
    #include <iostream>
    #include <string>
    class Base1
    {
    public:
        virtual void f(){
            std::cout << "Base1::f()" << std::endl;
        }
        virtual void g(){
            std::cout << "Base1::g()" << std::endl;
        }
        virtual void h(){
            std::cout << "Base1::h()" << std::endl;
        }
    };
    
    class Base2
    {
    public:
        virtual void f(){
            std::cout << "Base2::f()" << std::endl;
        }
        virtual void g(){
            std::cout << "Base2::g()" << std::endl;
        }
        virtual void h(){
            std::cout << "Base2::h()" << std::endl;
        }
    };
    
    class Base3
    {
    public:
        virtual void f(){
            std::cout << "Base3::f()" << std::endl;
        }
        virtual void g(){
            std::cout << "Base3::g()" << std::endl;
        }
        virtual void h(){
            std::cout << "Base3::h()" << std::endl;
        }
    };
    
    class Derived : public Base1, public Base2, public Base3
    {
    public:
        virtual void f(){
            std::cout << "Derived::f()" << std::endl;
        }
        virtual void g1(){
            std::cout << "Derived::g1()" << std::endl;
        }
        virtual void h1(){
            std::cout << "Derived::h1()" << std::endl;
        }
    };
     

    虚函数表

    图片 继承关系

    图片

    • 多层继承的情况
    #include <iostream>
    #include <string>
    class Base
    {
    public:
        virtual void f(){
            std::cout << "Base::f()" << std::endl;
        }
        virtual void g(){
            std::cout << "Base::g()" << std::endl;
        }
        virtual void h(){
            std::cout << "Base::h()" << std::endl;
        }
    };
    
    class Derived : public Base
    {
    public:
        virtual void f(){
            std::cout << "Derived::f()" << std::endl;
        }
        virtual void g1(){
            std::cout << "Derived::g1()" << std::endl;
        }
    };
    
    class DDerived : public Derived
    {
    public:
        virtual void f(){
            std::cout << "DDerived::f()" << std::endl;
        }
        virtual void h(){
            std::cout << "DDerived::h()" << std::endl;
        }
        virtual void g2(){
            std::cout << "DDerived::g2()" << std::endl;
        }
    };
    
    int main(int argc, char* argv[])
    {
        DDerived dd;
        dd.f();
    }
     
    • 继承关系

      图片

    • 虚函数表

      图片

虚继承模型

菱形继承问题C++的多继承是指从多个直接基类中产生派生类的能力,多继承的派生类继承了所有父类的成员。从概念上来讲这是非常简单的,但是多个基类的相互交织可能会带来错综复杂的设计问题,命名冲突就是不可回避的一个,比如典型的是菱形继承,如图所示:

图片

代码

#include <iostream>
#include <stdint.h>
class A{
public:
    long a;
};

class B: public {
public:
    long b;
};


class C: public A{
public:
    long c;
};

class D: public B, public C{
public:
    void seta(long v) { a = v; } // 命名冲突
    void setb(long v) { b = v; } // 正确
    void setc(long v) { c = v; } // 正确
    void setd(long v) { d = v; } // 正确

private:
    long d;
};

int main(int argc, char* argv[])
{
    D d;
}
 

变量(类型为D)d的内存布局,如下图所示: 图片

  • 为了解决多继承时命名冲突和冗余数据的问题,C++提出了虚继承这个概念,虚继承可以使得在派生类中只保留一份间接基类的成员。使用方式就是在继承方式前面加上virtual关键字修饰,示例代码如下(基于前面的例子修改):
#include <iostream>
#include <stdint.h>
class A{
public:
    long a;
};

class B: virtual public A{
public:
    long b;
};


class C: virtual public A{
public:
    long c;
};

class D: public B, public C{
public:
    void seta(long v) { a = v; } // 现在不会冲突了
    void setb(long v) { b = v; } // 正确
    void setc(long v) { c = v; } // 正确
    void setd(long v) { d = v; } // 正确

private:
    long d;
};

int main(int argc, char* argv[]){
    D d;
}
 

继承图

图片

类B的内存布局:

 

类D的内存布局

 

posted @ 2024-10-08 15:45  daligh  阅读(5)  评论(0编辑  收藏  举报