精华内容
下载资源
问答
  • 继承机制是对象对象程序设计使代码可以复用的重要手段,允许程序员在保持原有类特性的基础上进行扩展,产生新类,称为派生类,以前的学的都是函数复用,继承是类设计层次的复用。 继承的定义 Base类是父类,也称为...

    1. 继承的概念和定义

    1.1 继承的概念

      继承机制是对象对象程序设计使代码可以复用的重要手段,允许程序员在保持原有类特性的基础上进行扩展,产生新类,称为派生类,以前的学的都是函数复用,继承是类设计层次的复用。

    1.2 继承的定义

      Base类是父类,也称为基类,D类称为子类,也称为派生类。继承方式有public继承,protected继承,private继承。

    类成员/继承方式public继承protected继承private继承
    基类的public成员派生类的public成员派生类的protected派生类的private成员
    基类的protected成员派生类的protected派生类的protected成员派生类的private成员
    基类的private成员在派生类中不可见在派生类中不可见在派生类中不可见

    总结:
      1.基类的private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见指的是基类的私有成员被继承到了派生类对象当中,但是无论是在派生类的类内还是类外都是不能去访问的。
      2.基类的成员不想在类外被直接访问,但需要在派生类当中能访问,就定义为protected。保护成员限定符就是因为继承才出现的。
      3.public>protected>private
      4.使用关键字class时默认的继承方式时private,使用struct时默认的继承方式是public,不过最好显示写出继承方式。
      5.实际运用中一般都是使用public继承,很少也不提倡用protected/private继承。

    1.3 代码

    class Base
    {
    public:
    	Base()
    	{
    		cout << "Base::Base()" << endl;
    	}
    	~Base()
    	{
    		cout << "Base::~Base()" << endl;
    	}
    };
    
    class D : public Base
    {
    public:
    	D()
    	{
    		cout << "D::D()" << endl;
    	}
    	~D()
    	{
    		cout << "D::~D()" << endl;
    	}
    };
    
    int main()
    {
    	D d;
    
    	return 0;
    }
    

    在这里插入图片描述

    2. 基类和派生类对象的赋值转换(赋值兼容原则)

      1.派生类对象可以赋值给基类的对象/基类的指针/基类的引用(切片或者切割)。
      2.基类对象不能赋值给派生类对象
      3.基类的指针可以通过强制类型转换赋值给派生类的指针,但必须是基类的指针指向派生类对象的时候才是安全的。如果基类是多态类型,可以使用RTT的dynamic cast来进行识别后进行安全转换。

    代码

    class Base
    {
    public:
    	Base()
    	{
    		cout << "Base::Base()" << endl;
    	}
    	~Base()
    	{
    		cout << "Base::~Base()" << endl;
    	}
    private:
    	int a;
    };
    
    class D : public Base
    {
    public:
    	D()
    	{
    		cout << "D::D()" << endl;
    	}
    	~D()
    	{
    		cout << "D::~D()" << endl;
    	}
    private:
    	int b;
    };
    
    int main()
    {
    	D d;
    	Base* b = &d;
    
    	return 0;
    }
    

    在这里插入图片描述

    3. 继承中的作用域

      1.在继承体系中基类和派生类都有独立的作用域。
      2.子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫做隐藏,也叫重定义,在子类成员函数中,可以使用基类::基类成员显示访问。
      3.成员函数的隐藏,只需要函数名相同。
      4.在实际中在继承体系里最好不要定义同名的成员。

    代码

    class Base
    {
    public:
    	Base()
    	{
    		cout << "Base::Base()" << endl;
    	}
    	~Base()
    	{
    		cout << "Base::~Base()" << endl;
    	}
    	void fun(int, int)
    	{}
    private:
    	int a;
    };
    
    class D : public Base
    {
    public:
    	D()
    	{
    		cout << "D::D()" << endl;
    	}
    	~D()
    	{
    		cout << "D::~D()" << endl;
    	}
    	void fun(int)
    	{}
    private:
    	int b;
    };
    
    int main()
    {
    	D d;
    	Base b;
    	d.fun(3);
    	b.fun(2, 3);
    	//d.fun(2, 3); //被隐藏了
    	d.Base::fun(2, 3);
    
    	return 0;
    }
    

    4. 派生类的默认成员函数

      1.派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员,如果基类没有默认构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。
      2.派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
      3.派生类的析构函数会在被调用完成之后自动调用基类的析构函数清理基类的成员,这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。
      4.派生类的operator=必须要调用基类的operator=完成基类的复制
      5.派生类对象初始化先调用基类构造再调用派生类构造。
      6.派生类对象析构清理先调用派生类析构再调用基类的析构。

    5. 继承与友元

      1.友元关系不能继承,基类友元不能访问子类私有和保护成员。

    6. 继承与静态成员

      基类定义了static静态成员,则整个继承体系里面只有一个这样的成员,无论多少个子类,都只有一个static成员实例。

    7. 菱形继承及菱形虚拟继承

      1.单继承:一个子类只有一个直接父亲时称这个继承关系为单继承。
      2.多继承:一个子类有两个或者以上直接父类时称这个继承关系为多继承。
      3.菱形继承:菱形继承是多继承的一种特殊情况。
      4.菱形继承的问题:从对象成员模型构造,可以看出菱形继承有数据冗余和二义性的问题,在Assistant的对象中Person成员会有两份。
      5.虚拟继承可以解决菱形继承的二义性和数据冗余的问题。如果在Student和Teacher的继承Person时使用虚拟继承,即可解决问题。
    在这里插入图片描述
    代码

    class A
    {
    public:
    	A()
    	{
    		cout << "A::A()" << endl;
    	}
    	~A()
    	{
    		cout << "~A::A()" << endl;
    	}
    	void fun(int)
    	{
    		cout << "A::fun()" << endl;
    	}
    private:
    	int a = 1;
    };
    
    class B : public A
    {
    public:
    	B()
    	{
    		cout << "B::B()" << endl;
    	}
    	~B()
    	{
    		cout << "~B::B()" << endl;
    	}
    	virtual void fun(double)
    	{
    		cout << "B::fun()" << endl;
    	}
    private:
    	int b = 2;
    };
    
    class C : public A
    {
    public:
    	C()
    	{
    		cout << "C::C()" << endl;
    	}
    	~C()
    	{
    		cout << "C::C()" << endl;
    	}
    	virtual void fun(double)
    	{
    		cout << "C::fun()" << endl;
    	}
    private:
    	int c = 3;
    };
    
    class D : public B, public C
    {
    public:
    	D()
    	{
    		cout << "D::D()" << endl;
    	}
    	~D()
    	{
    		cout << "D::~D()" << endl;
    	}
    	void fun(double)
    	{
    		cout << "D::fun()" << endl;
    	}
    private:
    	int d = 4;
    };
    
    int main()
    {
    	D d;
    	return 0;
    }
    

    在这里插入图片描述
      这里时通过了B和C两个指针,指向了一张表,这两个指针叫做虚基表指针,这两个表叫做虚基表,虚基表中存的偏移量,通过偏移量可以找到下面的A。

    8. 继承的总结和反思

      1.有了多继承,就存在菱形继承,有了菱形继承就有了菱形虚拟继承,底层实现上就很复杂,因此一般不建议设计出菱形继承,否则在复杂度及性能上会有问题。
      2.继承和组合

    • public继承是一种is-a的关系,每个派生类对象都是一个基类对象。
    • 组合是一种has-a的关系,假设B组合了A,每个对象中都有一个A对象。
    • 优先使用对象组合,而不是类继承。
    • 继承允许根据基类的实现来定义派生类的实现,通过生成派生类的复用通常称为白箱复用,术语“白箱”是相对可视化而言的,在继承方式中,基类的内部细节对子类可见,继承一定程度破坏了基类的封装,基类的改变,对派生类有很大影响,派生类和基类间的依赖关系很强,耦合度高。(目标:高内聚,低耦合)
    • 对象组合是类继承之外的另一种复用选择,新的更复杂的功能可以通过组装或者组合对象来获得,对象组合要求被组合的对象具有良好定义的接口,这种复用风格被称为黑箱复用,对象的内部细节是不可见的,组合类之间没有很强的依赖关系,耦合度低,优先使用对象组合有助于保持每个类被封装。

    9. 虚函数表

      对于了解C++的人来说,应该都知道虚函数是通过一张虚函数表实现的,简称V-Table。在这个白哦中,主要是一个类的虚函数的地址表,这个表解决了继承和覆盖的问题,当我们用父类指针操作子类的时候,可以通过这张虚函数表指明了实际所应该调用的函数。
      在C++的标准规格说明书中说到,编译器必须要保证虚函数表的指针存在于对象实例中最前面的位置,为了获取正确的虚函数偏移量,通过变量里面的函数指针,就可以调用相应的函数。
    在这里插入图片描述
      当存在多重继承有虚函数覆盖的时候,类实例中的虚函数表的图。
    在这里插入图片描述

    10. 面试题

      1.什么是菱形继承?菱形继承的问题是什么?
      2.什么是菱形虚拟继承?如果解决数据冗余和二义性?
      3.继承和组合的区别?什么时候用继承?什么时候用组合?

    展开全文
  • C++多态 菱形继承 虚基表指针与虚基表 ...虚函数表指针与虚函数表(虚表) 在类中成员函数实现多态时,需要将成员函数定义为虚函数,所以,在多态的情景下,单继承下会存在一个虚函数表指针,指向成员函数...

    C++多态

    菱形继承

    虚基表指针与虚基表

    在这里插入图片描述
    我们知道,在虚继承(菱形继承)中,对于类D创建的对象d,为了避免A类中的变量重复,所以,将A类中成员变量放在d对象模型的最下面,由B类与C类各自虚基表指针访问虚基表中偏移量的方式进行访问A类成员变量
    在这里插入图片描述

    虚函数表指针与虚函数表(虚表)

    在类中成员函数实现多态时,需要将成员函数定义为虚函数,所以,在多态的情景下,单继承下会存在一个虚函数表指针,指向成员函数地址;多继承下,会根据继承基类的个数生成相应的多个虚函数表指针 ,从而访问虚函数的地址
    单继承下类对象模型👇 在这里插入图片描述
    多重继承下类对象模型
    在这里插入图片描述

    既有虚基表指针也有虚表指针的情况下对象模型

    class A
    {
    public:
    	virtual void Func()
    	{
    		cout << "A::Func()" << endl;
    	}
    protected:
    	int _a = 1;
    };
    
    class B : virtual public A
    {
    public:
    	virtual void Func()
    	{
    		cout << "B::Func()" << endl;
    	}
    protected:
    	int _b = 2;
    };
    
    class C : virtual public A
    {
    public:
    	virtual void Func()
    	{
    		cout << "C::Func()" << endl;
    	}
    protected:
    	int _c = 3;
    };
    
    class D : public B, public C
    {
    public:
    	virtual void Func()
    	{
    		cout << "D::Func()" << endl;
    	}
    protected:
    	int _d = 4;
    };
    int main()
    {
    	D d;
    	return 0;
    }
    

    在这里插入图片描述
    可以看到,类D对象d中的父类A中有成员变量,和一个_vfptr指针,接下来,我们再来看看内存布局:
    在这里插入图片描述
    发现,虚函数表指针只存放在基类A中有一份
    如下所示,即为虚拟继承中多态虚函数下的类对象模型。
    在这里插入图片描述

    展开全文
  • 还有一点,在多重继承下,所有基类的虚函数指针虽然都会被保留到派生类中,但是他们的偏移量都会被设置成第一个虚函数表指针,而且第一个虚函数表指针指向当前对象的虚函数表。 ------------ 又试了一下,虚拟...

    本文基于VS2012编译器,不同的编译器结果可能有较大出入

    来看这样一段代码

    class A
    { };
    class C:virtual public A
    { };
    class B:virtual public A
    { };
    class D:public C,public B
    { };
    int main ()
    {
    	cout<<sizeof(A)<<endl;
    	cout<<sizeof(C)<<endl;
    	cout<<sizeof(B)<<endl;
    	cout<<sizeof(D)<<endl;
    }

    最简单的菱形继承,C和B中因为virtual继承了A,所以内含一个虚基类指针指向A,A由编译器自动填充一个char

    运行结果

    D继承了C和B,拥有C和B包含的成员变量,两个虚基类指针,而且在当前环境下,A被布局在D的尾部,详情如下

    1>  class A    size(1):
    1>      +---
    1>      +---

    1>  class C    size(4):
    1>      +---
    1>   0    | {vbptr}
    1>      +---
    1>      +--- (virtual base A)
    1>      +---
    1>  

    1>  class B    size(4):
    1>      +---
    1>   0    | {vbptr}
    1>      +---
    1>      +--- (virtual base A)
    1>      +---
    1>  

    1>  class D    size(8):
    1>      +---
    1>      | +--- (base class C)
    1>   0    | | {vbptr}
    1>      | +---
    1>      | +--- (base class B)
    1>   4    | | {vbptr}
    1>      | +---
    1>      +---
    1>      +--- (virtual base A)
    1>      +---
    1>  

    事实和我们的预测符合,接下来引入虚函数

    class A
    { };
    class C:virtual public A
    {
    public:
    	virtual void fun(){ }
    };
    class B:virtual public A
    {
    public:
    	virtual void fun(){ }
    };
    class D:public C,public B
    {
    public:
    	virtual void fun(){ }
    };
    int main ()
    {
    	cout<<sizeof(A)<<endl;
    	cout<<sizeof(C)<<endl;
    	cout<<sizeof(B)<<endl;
    	cout<<sizeof(D)<<endl;
    }

    现在C里除了虚基类指针还有一个虚函数表指针,B同理,D继承来自两个具有虚函数的类,所以D里也会有两个虚函数表指针,

    加上B和C的虚基类指针,一共16

    结果如下

    1>  class A    size(1):
    1>      +---
    1>      +---
    1>  


    1>  
    1>  class C    size(8):
    1>      +---
    1>   0    | {vfptr}
    1>   4    | {vbptr}
    1>      +---
    1>      +--- (virtual base A)
    1>      +---
    1>  
    1
    1>  
    1>  class B    size(8):
    1>      +---
    1>   0    | {vfptr}
    1>   4    | {vbptr}
    1>      +---
    1>      +--- (virtual base A)
    1>      +---
    1>  

    1>  
    1>  class D    size(16):
    1>      +---
    1>      | +--- (base class C)
    1>   0    | | {vfptr}
    1>   4    | | {vbptr}
    1>      | +---
    1>      | +--- (base class B)
    1>   8    | | {vfptr}
    1>  12    | | {vbptr}
    1>      | +---
    1>      +---
    1>      +--- (virtual base A)
    1>      +---
     

    可是如果把上边A类的代码中加入一个虚函数

    class A
    {
    public:
    	virtual void fun() { }
    };

    会产生意想不到的结果

    D的大小居然变成了12,百思不得其解,只能求助于编译器

    1>  class A    size(4):
    1>      +---
    1>   0    | {vfptr}
    1>      +---
    1>  

    1>  
    1>  class C    size(8):
    1>      +---
    1>   0    | {vbptr}
    1>      +---
    1>      +--- (virtual base A)
    1>   4    | {vfptr}
    1>      +---
    1>  

    1>  
    1>  class B    size(8):
    1>      +---
    1>   0    | {vbptr}
    1>      +---
    1>      +--- (virtual base A)
    1>   4    | {vfptr}
    1>      +---
    1>  

    1>  
    1>  class D    size(12):
    1>      +---
    1>      | +--- (base class C)
    1>   0    | | {vbptr}
    1>      | +---
    1>      | +--- (base class B)
    1>   4    | | {vbptr}
    1>      | +---
    1>      +---
    1>      +--- (virtual base A)
    1>   8    | {vfptr}
    1>      +---
    1>  

    忽视了很重要的一点,当派生类在执行自己的构造函数的时候,修改的是第一个继承的基类的虚函数表指针,也就是说B和C在继承A的时候,使用的指针是原本属于A的,是A的成员变量,B和C并没有生成自己的虚函数表指针。又因为虚继承的原因,保证了虚基类在派生类中只有唯一一个实例,所以到了D中,B和C的虚函数表就被诡异的合成了一个,而且其中已经被D改写为指向自己的虚函数表。bravo~

    还有一点,在多重继承下,所有基类的虚函数指针虽然都会被保留到派生类中,但是他们的偏移量都会被设置成第一个虚函数表指针,而且第一个虚函数表指针指向当前对象的虚函数表。

    ------------

    又试了一下,虚拟继承的子类如果有新定义的虚函数,内部还是会有自己的虚函数表指针,也就是说虽然只有一个基类,但是子类却还是会有两个虚函数表指针,十分复杂。

    引用一下Lippman在书中的话  “我的建议是,不要再一个virtual base class中声明nonstatic data members。如果这么做,你会距离复杂的深渊愈来愈近,终不可拔。”

    展开全文
  • 菱形继承中的虚函数表 class A { public: virtual void func1() { cout << "A::func1" << endl; } private: int _a; }; class B :public A{ public: virtual void func1() { cout << "B::func...

    菱形继承中的虚函数表

    class A {
    public:
    	virtual void func1() { cout << "A::func1" << endl; }
    private:
    	int _a;
    };
    
    class B :public A{
    public:
    	virtual void func1() { cout << "B::func1" << endl; }
    	virtual void func2() { cout << "B::func2" << endl; }
    private:
    	int _b;
    };
    class C :public A{
    public:
    	virtual void func1() { cout << "C::func1" << endl; }
    	virtual void func2() { cout << "C::func2" << endl; }
    private:
    	int _c;
    };
    class D : public B, public C {
    public:
    	virtual void func1() { cout << "D::func1" << endl; }
    	virtual void func3() { cout << "D::func3" << endl; }
    private:
    	int _d;
    };
    
    typedef void(*VFPTR)();//虚函数指针
    void Print(VFPTR *arr)
    {
    	for (int i = 0; arr[i] != nullptr; ++i)
    	{
    		printf("第%d个虚函数地址:%0x\n",i, arr[i]);
    		arr[i]();
    	}
    }
    
    int main()
    {
    	D d;
    	VFPTR* arr1 = (VFPTR*)(*(int*)&d);//虚表指针(虚函数指针数组)
    	VFPTR* arr2 = (VFPTR*)(*(((int*)&d)+3));//第二个虚表指针偏移量
    	Print(arr1);
    	Print(arr2);
    	return 0;
    }	
    
    • 如下图,d对象是有两个虚表的
      在这里插入图片描述
    • 两个虚表中都不一定只有一个虚函数,vs在这里是无法看到子类新增加的虚函数。
    • 我们将第一个虚表地址所在的地址加上偏移量即可求得第二个虚表地址的地址。将他们虚表内容打印出来或者运行虚函数。
      在这里插入图片描述
    • 可以看出菱形继承派生类的新增加的虚函数放在第一个继承基类部分的虚函数表中。
    • 子类重写Func1时,把B和C两个类中的虚函数都重写了。

    菱形虚拟继承中的虚函数表

    class A {
    public:
    	virtual void func1() { cout << "A::func1" << endl; }
    private:
    	int _a=1;
    };
    
    class B :virtual public A{
    public:
    	virtual void func1() { cout << "B::func1" << endl; }
    	virtual void func2() { cout << "B::func2" << endl; }
    private:
    	int _b=2;
    };
    class C :virtual public A{
    public:
    	virtual void func1() { cout << "C::func1" << endl; }
    	virtual void func2() { cout << "C::func2" << endl; }
    private:
    	int _c=3;
    };
    class D : public B, public C {
    public:
    	virtual void func1() { cout << "D::func1" << endl; }
    	virtual void func3() { cout << "D::func3" << endl; }
    private:
    	int _d=4;
    };
    
    • 如下图是对象d的结构
      在这里插入图片描述
    • 这样看起来很难受,太乱了,无法具体判断。
    • 我们可以根据菱形继承的模型来推导菱形虚拟继承的结构模型
    • 下图是菱形继承的模型
      在这里插入图片描述
    • 根据上图,我们可以推导出菱形虚拟继承的结构模型如下
      在这里插入图片描述
    • 因为A类中的Func1()函数和_a变量都是冗余的,因此在虚拟继承中都会放在对象组成的最下面,他们同时属于B和C.
    • B和C则通过虚基表指针,通过偏移量找到_a。
    • 至于_a和A::Func1()谁先放在对象组成的后面,我们可以通过内存看见是A::Func1()先放在对象组成的后面。
      在这里插入图片描述
    • 下面我们通过代码来验证一下
    typedef void(*VFPTR)();//虚函数指针
    void Print(VFPTR *arr)
    {
    	for (int i = 0; arr[i] != nullptr; ++i)
    	{
    		printf("第%d个虚函数地址:%0x\n",i, arr[i]);
    		arr[i]();
    	}
    }
    
    int main()
    {
    	D d;
    	VFPTR* vfptr1 = (VFPTR*)(*(int*)&d);//第一个虚表
    	VFPTR* vfptr2 = (VFPTR*)(*(((int*)&d) + 3));//第二个虚表
    	VFPTR* A_Func1 = (VFPTR*)(*(((int*)&d) + 7));//A::Func1()在对象组成后面的函数指针
    	
    	Print(vfptr1);
    	Print(vfptr2);
    
    	printf("A::Func1()地址:%0x\n", (int*)A_Func1);
    	(*A_Func1)();//调用函数
    	
    	return 0}
    

    在这里插入图片描述

    • 我们可以看出来两个虚表中都没有了Func1()的函数指针,也的确是放在对象组成的下面。消除了二义性。
    展开全文
  • 菱形继承虚函数表

    千次阅读 2017-02-22 20:21:25
    虚函数:类的成员函数前面加virtual 虚函数的主要作用就是实现多态 ...虚函数表(虚表):通过一片连续的地址来储存虚函数的地址 菱形继承举例:#include using namespace std; class AA { public:
  • 继承:只有一个基类和一个派生类 class Base { public: virtual void fun1() { cout "Base::func1()" ; } virtual void fun2() { cout "Base::func2()" ; } private:
  • 最近被问到一个关于多继承虚函数表的问题,当时回答是可能存在多个虚函数表,应该是顺序排列的,但具体怎么排列还是有些疑惑的,回答的时候到有点儿心虚。之后查了资料,做了简单的实验,可以确定的是对于继承了多个...
  • https://blog.csdn.net/j4ya_/article/details/80177897
  • 下面我们先接着上次讲有虚函数菱形继承首先什么是虚函数。?虚函数:在类里面,函数前面有virtual关键字的成员函数就是虚函数。代码块:class base { public: base() { cout &lt;&lt; "base()&...
  • 读者注意:阅读这篇文章时,对继承中的对象模型要有一定了解;觉得自己不确定的话单击下面的“继承”。继承多态多态按字面的意思就是“多种状态”。在面向对象语言中,接口的多种不同的实现方式即为多态。直白点理解...
  • 菱形继承:650) this.width=650;" src="http://s1.51cto.com/wyfs02/M02/7E/9B/wKiom1cFDbHDMc8eAAAx4qLLT30181.png" title="QQ图片20160406212235.png" alt="wKiom1cFDbHDMc8eAAAx4qLLT30181.png" />Assitant的菱形...
  • 虚函数、虚函数表指针、虚函数表、多级继承、多重继承、菱形继承
  • c++单继承、多继承、菱形继承内存布局(虚函数表结构)
  • 一、虚函数 类中用virtual关键字修饰的函数。 作用:主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有...
  • 继承:只有一个基类和一个派生类 class Base { public: virtual void fun1() { cout "Base::func1()" ; } virtual void fun2() { cout "Base::func2()" ; } private:
  • 菱形继承虚函数

    千次阅读 2017-10-11 17:28:37
    此篇博客主要介绍菱形虚拟继承虚函数的混合情况下的模型分析。 一首先介绍一下虚函数的实质内容 代码如下 class A { public: int a; virtual void fun1() { cout ; } }; class B :public A { public: int b...
  • 解析虚函数表和虚继承

    千次阅读 多人点赞 2016-10-31 11:48:56
    之前大二在学C++的时候一直对虚函数和虚继承有些晕(其实好像就是对virtual这个关键字不太熟悉)现在又学习到了一些,对虚函数表和虚继承的机制有了一点更深入的了解。 关于虚函数以及虚继承的基础知识,我自己也...
  • 大家看到标题,会不会菱形继承虚表会不会是重复的呢?祖父类的虚表会不会在子类会不会是两份相同呢?那么我们一起来探索一下吧,冲冲冲!! 首先我们来分析一下: 它一共定义了四个类,分别为CFurniture,CSofa...
  • title: C++多继承时的虚函数表结构 date: 2020-09-26 17:40:36 description: 一个多继承虚函数表的结构的例子  C++为了实现运行时的多态,引入了虚函数的概念。为了实现运行时多态的,其底层一般采用虚函数表来...
  • 一、菱形继承那就先从菱形继承开始复习如下代码:#include&lt;iostream&gt; using namespace std; class A { public: int _a; }; class B : public A { public: int _b; }; class C : public A { ...
  • 这里测试了一下多重继承,加菱形继承,加虚继承的代码,并输出了他们的虚函数表,不多bb,看代码看结果吧。 #include <iostream> #include <cstdio> #include <iomanip> #include <string>...
  • 访问菱形继承时的虚函数表 #include <iostream> #include <cstdio> #include <iomanip> #include <string> #include <cstdlib> #include <cstring> #include <queue> #...
  • 对于某些函数来说,基类希望它的派生类定义适合自身的版本,此时基类就将这些函数声明为虚函数。...【带有虚函数菱形继承】 以下图的模型为例进行分析: class A { public : A() :a(1) {}
  • 构造函数和析构函数里面可以调用虚函数吗?写个例子测试一下就知道这并没什么问题,程序也许可能按预期正常执行,但是语法上通过的东西...《深度探索C++对象模型》一书中分析了对象的创建过程,括构造虚函数表的时机。
  • 继承:只有一个基类和一个派生类 class Base { public: virtual void fun1() ...
  • 这样就叫做菱形继承也叫钻石继承(Diamond inheritance)上代码块:#define _CRT_SECURE_NO_WARNINGS 1 #include&lt;stdio.h&gt; #include&lt;iostream&gt; using namespace std; class A { public...
  • C++ 多重继承继承 虚函数表 多态

    千次阅读 2016-03-25 15:05:11
    这中间包括了运行时多态,虚函数表等等相关概念。 多重继承,顾名思义,是一个类继承了多个父类。例如class C:public A, publicB{};这样就是一个多重继承。 首先看看多重继承的构造和析构函数。 多重继承的构造...
  • 需要通过虚函数+封装+继承实现。 虚函数 1、虚函数都必须有定义 2、虚函数一般用在继承中。多个子类继承同一基类,若在某种行为上不同的派生类有着自己的实现方式。这种情况我们就会用到多态。采用在基类中将此...
  • 菱形继承的对象模型、继承的对象模型、以及深入探究基表的内容,为什么基表存放对象的偏移量要存放在第二个位置,而不是第一个位置?

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,472
精华内容 1,788
关键字:

菱形继承虚函数表