精华内容
下载资源
问答
  • #include "stdafx.h" #include using namespace std; class Base { public : virtual ~Base();//析构函数做成员函数 };...Base::~Base()//成员函数实现 ...//从堆上分配一个int型变量所占的字节内存,这个内存单元存放的...
  • C++虚基类

    千次阅读 2018-06-29 10:55:29
    可以使用作用域分辨符来来存放不同数据、进行不同操作,但也可以通过虚基类来维护一个成员副本。将共同基类设置为虚基类,这时不同路径继承过来的同名数据成员在内存中就只有一个副本,同一个函数名也只有一个映射。...

    可以使用作用域分辨符来来存放不同数据、进行不同操作,但也可以通过虚基类来维护一个成员副本。将共同基类设置为虚基类,这时不同路径继承过来的同名数据成员在内存中就只有一个副本,同一个函数名也只有一个映射。

    虚基类成员在派生过程中和派生类一起维护同一个内存数据副本,这一点其实很好理解。

    我们先来看一下没有声明虚基类的程序:

    #include <iostream>
    using namespace std;
    
    class Base0{
        public:
            int var0;
            void fun0(){cout<<"Member of Base0"<<endl;}
    };
    
    class Base1:public Base0{
        public:                                //新增外部接口
            int var1;
    };
    
    class Base2:public Base0{
        public:                                //新增外部接口
            int var2;
    };
    
    class Derived:public Base1,public Base2{
        public:                                //新增外部接口
            int var;
            void fun(){cout<<"Member of Derived"<<endl;}
    };
    
    int main(){
        Derived d;
        d.var0=2;
        d.fun0();
        return 0;
    }

    程序显然无法成功运行,错误原因:request for member 'var0'(fun0) is ambiguous(不明确的),因为Base1和Base2都有var0fun0(),程序不知道你调用的是哪一个类继承下来的,除非你用作用域分辩符来唯一标识,写成:

        d.Base1::var0=2;
        d.Base1::fun0();
        d.Base2::var0=3;
        d.Base2::fun0();

    这样Base1和Base2类下的数据就分开存储了,当然我们也可以使用虚基类技术进行共同存储,也就是这几个类共用一个var0fun0副本,能节省不少内存空间。

    虚基类的声明只是在类派生过程中使用virtual关键字,代码如下:

    #include <iostream>
    using namespace std;
    
    class Base0{
        public:
            int var0;
            void fun0(){cout<<"Member of Base0"<<endl;}
    };
    
    class Base1:virtual public Base0{         
        public:                                //新增外部接口
            int var1;
    };
    
    class Base2:virtual public Base0{
        public:                                //新增外部接口
            int var2;
    };
    
    class Derived:public Base1,public Base2{
        public:                                //新增外部接口
            int var;
            void fun(){cout<<"Member of Derived"<<endl;}
    };
    
    int main(){
        Derived d;
        d.var0=2;                     //直接访问虚基类的数据成员
        d.fun0();                     //直接访问虚基类的函数成员
        return 0;
    }

    这样一来,程序就能成功运行:
    这里写图片描述
    这时的Derived类中,通过Base1,Base2继承来的基类Base0中成员var0fun0只有一份副本,改变var0的值,就相当于改变Base1,Base2中的var0的值了。

    展开全文
  • c++实现虚基类

    2018-05-24 19:21:22
    (1)定义人员类Person: 公有成员:姓名(Name); 保护成员:性别(Gender),年龄(Age); 构造函数和析构函数 (2) 从人员类Person派生学生记录类StudentRecord: 添加公有成员:学号(Number),班级...
  • C++ 虚基类

    千次阅读 多人点赞 2021-05-13 12:07:25
    C++ 虚基类. 虚基类如何解决多重继承的问题.

    概述

    虚基类 (virtual base class) 是用关键字 virtual 声明继承的父类.
    在这里插入图片描述

    多重继承的问题

    N 类:

    class N {
    public:
        int a;
        void display(){
            cout << "A::a=" << a <<endl;
        }
    };
    

    A 类:

    class A : public N {
    public:
        int a1;
    };
    

    B 类:

    class B : public N {
    public:
        int a2;
    };
    

    C 类:

    class C: public A, public B{
    public:
        int a3;
        void display() {cout << "a3=" << a3 << endl;};
    };
    

    main:

    int main() {
        C c1;
        // 合法访问
        c1.A::a = 3;
        c1.A::display();
    
        return 0;
    }
    

    输出结果:

    A::a=3
    

    存在的问题:

    • A::a 和 B::a 是 N 类成员的拷贝
    • A::a 和 B::a 占用不同的空间

    在这里插入图片描述

    虚基类

    我们希望继承间接共同基类时只保留一份成员, 所以虚基类就诞生了. 当基类通过多条派生路径被一个派生类继承时, 该派生类只继承该基类一次.

    语法:

    class 派生类名: virtual 继承方式 基类名
    

    初始化

    通过构造函数的初始化表对虚拟类进行初始化. 例如:

    N 类:

    class N {
    public:
        int n;
        N(int n) : n(n) {};
    };
    

    A 类:

    class A : virtual public N {
    public:
        A(int n) : N(n) {};
    };
    

    B 类:

    class B : virtual public N {
    public:
        B(int n) : N(n) {};
    };
    

    C 类:

    class C: public A, public B{
    public:
        C(int n) : N(n), A(n), B(n){};
    };
    

    例子

    Person 类:

    #ifndef PROJECT5_PERSON_H
    #define PROJECT5_PERSON_H
    
    #include <iostream>
    #include <string>
    using namespace std;
    
    class Person {
    protected:
        string name;
        char gender;
    public:
        Person(string n, char g) : name(n), gender(g) {}
        void display() {
            cout << "name: " << name << endl;
            cout << "gender: " << gender << endl;
        }
    };
    
    #endif //PROJECT5_PERSON_H
    

    Student 类:

    #ifndef PROJECT5_STUDENT_H
    #define PROJECT5_STUDENT_H
    
    #include <string>
    #include "Person.h"
    using namespace std;
    
    class Student : virtual public Person {
    protected:
        double score;
    public:
        Student(string n, char g, double s) : Person(n, g), score(s) {};
    };
    
    #endif //PROJECT5_STUDENT_H
    

    Teacher 类:

    #ifndef PROJECT5_TEACHER_H
    #define PROJECT5_TEACHER_H
    
    #include <string>
    #include "Person.h"
    using namespace std;
    
    class Teacher : virtual public Person {
    protected:
        string title;
    public:
        Teacher(string n, char g, string t) : Person(n, g), title(t) {};
    };
    
    #endif //PROJECT5_TEACHER_H
    

    Graduate 类:

    #ifndef PROJECT5_GRADUATE_H
    #define PROJECT5_GRADUATE_H
    
    #include "Teacher.h"
    #include "Student.h"
    #include <string>
    using namespace std;
    
    class Graduate : public Teacher, public Student{
    private:
        double wage;
    public:
        Graduate(string n, char g, double s, string t, double w) : Person(n, g), Student(n, g, s), Teacher(n, g, t), wage(w) {};
        void display() {
            Person::display();
            cout << "score: " << score << endl;
            cout << "title: " << title << endl;
            cout << "wages: " << wage << endl;
        };
    };
    
    #endif //PROJECT5_GRADUATE_H
    

    main:

    #include <iostream>
    #include "Graduate.h"
    using namespace std;
    
    int main() {
        Graduate grad1("小白",'f',89.5,"教授",1234.5);
        grad1.display();
    
        return 0;
    }
    

    输出结果:

    name: 小白
    gender: f
    score: 89.5
    title: 教授
    wages: 1234.5
    

    总结

    • 使用多重继承时要十分小心, 否则会进场出现二义性问题
    • 不提倡在程序中使用多重继承
    • 只有在比较简单和不易出现二义性的情况或实在必要时才使用多重继承
    • 能用单一继承解决的问题就不要使用多重继承
      在这里插入图片描述
    展开全文
  • 主要介绍了详解C++中基类与派生类的转换以及虚基类,是C++入门学习中的基础知识,需要的朋友可以参考下
  • C++ 虚基类的定义、功能、规定

    千次阅读 2017-09-30 11:02:11
    虚继承和虚基类的定义是非常的简单的,同时也是非常容易判断一个继承是否是虚继承的,虽然这两个概念的定义是非常的简单明确的,但是在C++语言中虚继承作为一个比较生僻的但是又是绝对必要的组成部份而存在着,并且...
    原文声明:http://blog.sina.com.cn/s/blog_93b45b0f01011pkz.html
    

    虚继承和虚基类的定义是非常的简单的,同时也是非常容易判断一个继承是否是虚继承的,虽然这两个概念的定义是非常的简单明确的,但是在C++语言中虚继承作为一个比较生僻的但是又是绝对必要的组成部份而存在着,并且其行为和模型均表现出和一般的继承体系之间的巨大的差异(包括访问性能上的差异),现在我们就来彻底的从语言、模型、性能和应用等多个方面对虚继承和虚基类进行研究。

    首先还是先给出虚继承和虚基类的定义。
        虚继承:在继承定义中包含了virtual关键字的继承关系;
        虚基类:在虚继承体系中的通过virtual继承而来的基类,需要注意的是:class Base1 : public virtual Base0 {}; 其中Base0称之为Base1的虚基类,而不是说Base0就是个虚基类,因为Base0还可以不不是虚继承体系中的基类。
        有了上面的定义后,就可以开始虚继承和虚基类的本质研究了,下面按照语法、语义、模型、性能和应用五个方面进行全面的描述。

    1. 语法
           语法有语言的本身的定义所决定,总体上来说非常的简单,如下:

    class Base1 : public virtual Base0 {};
    其中可以采用public、protected、private三种不同的继承关键字进行修饰,只要确保包含virtual就可以了,这样一来就形成了虚继承体系,同时Base0就成为了Base1的虚基类了。其实并没有那么的简单,如果出现虚继承体系的进一步继承会出现什么样的状况呢?

           如下所示:

    class Base0
    {
    public:
        Base0(int i) : m_val( i ) {}
        int m_val;
    };
    class Base1 : public virtual Base0
    {
    public:
        Base1 (int i) : Base0( i ) {}
    };   
             
    class Base2 : public virtual Base0
    {
    public:
        Base2(int i) : Base0( i ) {}
    };     
           
    class Base3 : public Base1, public Base2
    {
    public:
        Base3(int i) : Base0( i ), Base1 ( i ), Base2 ( i ) {}
    }; 
               
    class Base4: public Base3
    {
    public:
        Base4 (int i) : Base0( i ), Base3( i ) {}
    };
    


    注意上面代码中的Base3和Base4两个类的构造函数初始化列表中的内容。可以发现其中均包含了虚基类Base0的初始化工作,如果没有这个初始化语句就会导致编译时错误,为什么会这样呢?一般情况下不是只要在Base1和Base2中包含初始化就可以了么?要解释该问题必须要明白虚继承的语义特征,所以参看下面语义部分的解释。
    2. 语义
           从语义上来讲什么是虚继承和虚基类呢?上面仅仅是从如何在C++语言中书写合法的虚继承类定义而已。
           首先来了解一下virtual这个关键字在C++中的公共含义,在C++语言中仅仅有两个地方可以使用virtual这个关键字,一个就是类成员虚函数和这里所讨论的虚继承。不要看这两种应用场合好像没什么关系,其实他们在背景语义上具有virtual这个词所代表的共同的含义,所以才会在这两种场合使用相同的关键字。
           那么virtual这个词的含义是什么呢?virtual在《美国传统词典[双解]》中是这样定义的:
               adj.(形容词)
               1. Existing or resulting in essence or effect though not in actual fact, form, or name:
                  实质上的,实际上的:虽然没有实际的事实、形式或名义,但在实际上或效果上存在或产生的;
               2. Existing in the mind, especially as a product of the imagination. Used in literary criticism of text.
                  虚的,内心的:在头脑中存在的,尤指意想的产物。用于文学批评中。
           我们采用第一个定义,也就是说被virtual所修饰的事物或现象在本质上是存在的,但是没有直观的形式表现,无法直接描述或定义,需要通过其他的间接方式或手段才能够体现出其实际上的效果。
           那么在C++中就是采用了这个词意,不可以在语言模型中直接调用或体现的,但是确实是存在可以被间接的方式进行调用或体现的。比如:虚函数必须要通过一种间接的运行时(而不是编译时)机制才能够激活(调用)的函数,而虚继承也是必须在运行时才能够进行定位访问的一种体制。存在,但间接。其中关键就在于存在、间接和共享这三种特征。
           对于虚函数而言,这三个特征是很好理解的,间接性表明了他必须在运行时根据实际的对象来完成函数寻址(C++中利用类指针*与引用&来完成多样性的重载),共享性表象在基类会共享被子类重载后的虚函数,其实指向相同的函数入口。
           对于虚继承而言,这三个特征如何理解呢?存在即表示虚继承体系和虚基类确实存在,间接性表明了在访问虚基类的成员时同样也必须通过某种间接机制来完成(下面模型中会讲到),共享性表象在虚基类会在虚继承体系中被共享,而不会出现多份拷贝。
           那现在可以解释语法小节中留下来的那个问题了,“为什么一旦出现了虚基类,就必须在每一个继承类中都必须包含虚基类的初始化语句”。
           由上面的分析可以知道,虚基类是被共享的,也就是在继承体系中无论被继承多少次,对象内存模型中均只会出现一个虚基类的子对象(这和多继承是完全不同的),这样一来既然是共享的那么每一个子类都不会独占,但是总还是必须要有一个类来完成基类的初始化过程(因为所有的对象都必须被初始化,哪怕是默认的),同时还不能够重复进行初始化,那到底谁应该负责完成初始化呢?C++标准中(也是很自然的)选择在每一次继承子类中都必须书写初始化语句(因为每一次继承子类可能都会用来定义对象),而在最下层继承子类中实际执行初始化过程。所以上面在每一个继承类中都要书写初始化语句,但是在创建对象时,而仅仅会在创建对象用的类构造函数中实际的执行初始化语句,其他的初始化语句都会被压制不调用。
     3. 模型
           为了实现上面所说的三种语义含义,在考虑对象的实现模型(也就是内存模型)时就很自然了。在C++中对象实际上就是一个连续的地址空间的语义代表,我们来分析虚继承下的内存模型。
           3.1. 存在
               也就是说在对象内存中必须要包含虚基类的完整子对象,以便能够完成通过地址完成对象的标识。那么至于虚基类的子对象会存放在对象的那个位置(头、中间、尾部)则由各个编译器选择,没有差别。(在VC8中无论虚基类被声明在什么位置,虚基类的子对象都会被放置在对象内存的尾部)
           3.2. 间接
               间接性表明了在直接虚基承子类中一定包含了某种指针(偏移或表格)来完成通过子类访问虚基类子对象(或成员)的间接手段(因为虚基类子对象是共享的,没有确定关系),至于采用何种手段由编译器选择。(在VC8中在子类中放置了一个虚基类指针vbc,该指针指向虚函数表中的一个slot,该slot中存放着虚基类子对象的偏移量的负值,实际上就是个以补码表示的int类型的值,在计算虚基类子对象首地址时,需要将该偏移量取绝对值相加,这个主要是为了和虚表中只能存放虚函数地址这一要求相区别,因为地址是原码表示的无符号int类型的值)
           3.3. 共享
               共享表明了在对象的内存空间中仅仅能够包含一份虚基类的子对象,并且通过某种间接的机制来完成共享的引用关系。在介绍完整个内容后会附上测试代码,体现这些内容。
        4. 性能
           由于有了间接性和共享性两个特征,所以决定了虚继承体系下的对象在访问时必然会在时间和空间上与一般情况有较大不同。
           4.1. 时间
               在通过继承类对象访问虚基类对象中的成员(包括数据成员和函数成员)时,都必须通过某种间接引用来完成,这样会增加引用寻址时间(就和虚函数一样),其实就是调整this指针以指向虚基类对象,只不过这个调整是运行时间接完成的。
               (在VC8中通过打开汇编输出,可以查看*.cod文件中的内容,在访问虚基类对象成员时会形成三条mov间接寻址语句,而在访问一般继承类对象时仅仅只有一条mov常量直接寻址语句)
           4.2. 空间
               由于共享所以不同在对象内存中保存多份虚基类子对象的拷贝,这样较之多继承节省空间。
        5. 应用
           谈了那么多语言特性和内容,那么在什么情况下需要使用虚继承,而一般应该如何使用呢?
           这个问题其实很难有答案,一般情况下如果你确性出现多继承没有必要,必须要共享基类子对象的时候可以考虑采用虚继承关系(C++标准ios体系就是这样的)。由于每 一个继承类都必须包含初始化语句而又仅仅只在最底层子类中调用,这样可能就会使得某些上层子类得到的虚基类子对象的状态不是自己所期望的(因为自己的初始化语句被压制了),所以一般建议不要在虚基类中包含任何数据成员(不要有状态),只可以作为接口类来提供。

    最后声明:c++中的虚基类对应java中的接口,Java中的接口则没有任何实现代码,而且接口里面的属性默认都是public static, 所有方法都是public 的。所以java用起来确实又很多方便之处。

    展开全文
  • c++虚基类在内存中的分布

    千次阅读 2017-08-03 14:19:18
    今天重温C++的知识,当看到虚基类这点的时候,那时候也没有太过追究,就是知道虚基类是消除了类继承之间的二义性问题而已,可是很是好奇,它是怎么消除的,内存布局是怎么分配的呢?于是就深入研究了一下,具体的...

    本文转自http://www.cnblogs.com/cy568searchx/p/3688215.html

    今天重温C++的知识,当看到虚基类这点的时候,那时候也没有太过追究,就是知道虚基类是消除了类继承之间的二义性问题而已,可是很是好奇,它是怎么消除的,内存布局是怎么分配的呢?于是就深入研究了一下,具体的原理如下所示:

    在C++中,obj是一个类的对象,p是指向obj的指针,该类里面有个数据成员mem,请问obj.mem和p->mem在实现和效率上有什么不同。
    答案是:只有一种情况下才有重大差异,该情况必须满足以下3个条件:
    (1)、obj 是一个虚拟继承的派生类的对象
    (2)、mem是从虚拟基类派生下来的成员
    (3)、p是基类类型的指针
    当这种情况下,p->mem会比obj.mem多了两个中间层。(也就是说在这种情况下,p->mem比obj.mem要明显的慢)
    WHY?
    如果好奇心比较重的话,请往下看 :
    1、虚基类的使用,和为多态而实现的虚函数不同,是为了解决多重继承的二义性问题。
    举例如下:
    class A
    {
    public:
        int a;
    };
    class B : virtual public A
    {
    public:
       int b;
    };
    class C :virtual public A
    {
    public:
       int c; 
    };
    class D : public B, public C
    {
    public:
       int d;
    };
    上面这种菱形的继承体系中,如果没有virtual继承,那么D中就有两个A的成员int a;继承下来,使用的时候,就会有很多二义性。而加了virtual继承,在D中就只有A的成员int a;的一份拷贝,该拷贝不是来自B,也不是来自C,而是一份单独的拷贝,那么,编译器是怎么实现的呢??
    在回答这个问题之前,先想一下,sizeof(A),sizeof(B),sizeof(C),sizeof(D)是多少?(在32位x86的linux2.6下面,或者在vc2005下面)在linux2.6下面,结果如下:sizeof(A) = 4; sizeof(B) = 12; sizeof(C) = 12; sizeof(D) = 24;sizeof(B)为什么是12呢,那是因为多了一个指针(这一点和虚函数的实现一样),那个指针是干嘛的呢?
    那么sizeof(D)为什么是24呢?那是因为除了继承B中的b,C中的c,A中的a,和D自己的成员d之外,还继承了B,C多出来的2个指针(B和C分别有一个)。再强调一遍,D中的int a不是来自B也不是来自C,而是另外的一份从A直接靠过来的成员。
    如果声明了D的对象d: D d;
    那么d的内存布局如下:
    vb_ptr: 继承自B的指针
    int b: 继承自B公有成员
    vc_ptr:继承自C的指针
    int c: 继承自C的共有成员
    int d: D自己的公有成员
    int a: 继承自A的公有成员
     
    那么以下的用法会发生什么事呢?
    D dD;
    B *pb = &dD;
    pb->a;
    上面说过,dD中的int a不是继承自B的,也不是继承自C的,那么这个B中的pb->a又会怎么知道指向的是dD内存中的第六项呢?
    那就是指针vb_ptr的妙用了。原理如下:(其实g++3.4.3的实现更加复杂,我不知道是出于什么考虑,而我这里只说原理,所以把过程和内容简单化了)
    首先,vb_ptr指向一个整数的地址,里面放的整数是那个int a的距离dD开始处的位移(在这里vb_ptr指向的地址里面放的是20,以字节为单位)。编译器是这样做的:
    首先,找到vb_ptr(这个不用找,因为在g++中,vb_ptr就是B*中的第一项,呵呵),然后取得vb_ptr指向的地址的内容(这个例子是20),最后把这个内容与指针pb相加,就得到pb->a的地址了。
    所以说这种时候,用指针转换多了两个中间层才能找到基类的成员,而且是运行期间。
    由此也可以推知dD中的vb_ptr和vc_ptr的内容都是一样的,都是指向同一个地址,该地址就放20(在本例中)
    如下的语句呢:
    A *pa = &dD;
    pa->a = 4;
    这个语句不用转换了,因为编译器在编译期间就知道他把A中的成员插在dD中的那个地方了(在本例中是末尾),所以这个语句中的运行效率和dD.a是一样的(至少也是差不多的)
    这就是虚基类实现的基本原理。
    注意的是:那些指针的位置和基类成员在派生类成员中的内存布局是不确定的,也就是说标准里面没有规定int a必须要放在最后,只不过g++编译器的实现而已。c++标准大概只规定了这套机制的原理,至于具体的实现,比如各成员的排放顺序和优化,由各个编译器厂商自己定~
     
    非虚拟继承:
     在派生类对象里,按照继承声明顺序依次分布基类对象,最后是派生类数据成员。
     若基类声明了虚函数,则基类对象头部有一个虚函数表指针,然后是基类数据成员。
     在基类虚函数表中,依次是基类的虚函数,若某个函数被派生类override,则替换为派生类的函数。
     派生类独有的虚函数被加在第一个基类的虚函数表后面。
     
       虚拟继承:
     在派生类对象里,按照继承声明顺序依次分布非虚基类对象,然后是派生类数据成员,最后是虚基类对象。
     若基类声明了虚函数,则基类对象头部有一个虚函数表指针,然后是基类数据成员。
     在基类虚函数表中,依次是基类的虚函数,若某个函数被派生类override,则替换为派生类的函数。
     若直接从虚基类派生的类没有非虚父类,且声明了新的虚函数,则该派生类有自己的虚函数表,在该派生类头部;否则派生类独有的虚函数被加在第一个非虚基类的虚函数表后面。
     直接从虚基类派生的类内部还有一个虚基类表指针(一个隐藏的“虚基类表指针”成员,指向一个虚基类表),在数据成员之前,非虚基类对象之后(若有的话)。
     虚基类表中第一个值是该 虚基类表到派生类起始地址的偏移;之后的值依次是该派生类的虚基类到该表位置的地址偏移(虚基类对象的地址与派生类的“虚基类表指针”之间的偏移量)。
     

    对于虚函数表指针和虚基类表指针:

    当单继承且非虚继承时:每个含有虚函数的表只有一个虚函数表,所以只需要一个虚表指针即可;

    当多继承且非虚继承时:一个子类有几个父类则会有几个虚函数表,所以就有和父类个数相同的虚表指针来标识;

    总之,当时非虚继承时,不需要额外增加虚函数表指针。

    当虚继承时:无论是单虚继承还是多虚继承,需要有一个虚基类表来记录虚继承关系,所以此时子类需要多一个虚基类表指针;而且只需要一个即可。

    当虚继承时可能出现一个类中持有多个虚函数表的情况:无论是单虚继承还是多虚继承,

    如果子类没有构造函数和析构函数,且子类中的虚函数都是在父类中出现的虚函数,这个时候不需要增加任何虚表指针;只需要像多继承那个持有父类个数的虚表指针来标识即可;

    如果子类中含有构造函数或者析构函数或二者都有,则在子类中只要每出现一个父类中的虚函数则需要增加一个虚函数表指针来标识此类的虚函数表;

    无论是否含有构造函数或者虚构函数,只要继承都是虚继承且出现了父类中没有出现的虚函数,则在子类中需要再增加一个徐函数表指针;如果其中有一个是非虚继承,则按照最省空间的原则,不需要增加虚函数表指针,因为这个时候可以和非虚基类共享一个虚函数表指针。
    展开全文
  • 但只有用于建立对象的最派生类的构造函数调用虚基类的构造函数,而该派生类的所有基类中列出的对虚基类构造函数的调用在执行中被忽略,从而保证对虚基类子对象只初始化一次。 7>在一个成员初始化列表中,同时...
  • C++虚基类和虚函数~

    2017-05-09 01:17:25
    一:虚基类 我们一般说定义虚基类,是因为为了去解决二义性的问题(在菱形结构中,由于一级派生类函数重名,二级派生类对象调用同名函数时程序产生两种或多种可能,有歧义,就产生了二义性问题;或者像基类的数据...
  • C++ 虚基类和抽象类关系

    千次阅读 2018-02-08 07:27:56
    虚基类:被“virtual”继承的类,也就是说任何类都可以成为虚基类。 抽象类:至少包含一个纯虚函数的类,其不能被实例化,哪怕该纯虚函数在该类中被定义。 二者没有任何联系。 二、源码 class CHuman { public:...
  • C++ 虚基类是什么

    千次阅读 多人点赞 2016-09-02 16:00:25
    这时候就要用到虚基类(虚继承)此时B和C继承的是同一个对象A,而不是2个A这样i都是来自于一个对象#include&lt;iostream&gt; using namespace std; class A { public: int i; void showa(){cou...
  • c++ 虚基类

    2015-03-01 18:08:26
    我们知道,如果一个派生类有多个直接基类,而这些直接基类又有一个共同的基类,则在最终的派生类中会保留该间接共同基类数据成员的多份同名成员。在引用这些同名的成员时,必须在派生类对象名后增加直接基类名,以...
  • 利用C++计算正方形,矩形,三角形圆形的面积,包含了函数,继承,多态相关的基础知识,这是一个示例程序力求简单易懂。代码采用VC6.0建立工程。
  • C++虚基类详解

    2014-11-17 14:49:55
    我们知道,如果一个派生类有多个直接基类,而这些直接基类又有一个共同的基类,则在最终的派生类中会保留该间接共同基类数据成员的多份同名成员。在引用这些同名的成员时,必须在派生类对象名后增加直接基类名,以...
  • C++虚基类的作用

    千次阅读 2015-10-16 22:49:52
    虚基类的作用   当一个基类被声明为虚基类后,即使它成为了多继承链路上的公共基类,最后的派生类中也只有它的一个备份。例如: class CBase { }; class CDerive1:virtual public CBase{ }; class CD
  • C++虚基类构造函数

    2016-06-14 16:12:06
    C++虚基类构造函数 下面文章详细介绍C++虚基,所谓C++虚基类:是由最派生类的构造函数通过调用虚基类的构造函数进行初始化的,但前提是要深入理解到底什么是C++虚基类,及他是怎么运行的。 前面讲过,为了初始化...
  • c++ 虚基类应用

    2019-09-28 19:14:02
    虽然这样可以解决二义性,但是相同的属性出现在多个基类中,为了解决数据冗余,c++引入了虚基类。  虚基类定义:class 派生类名: virtual 继承方式 基类名  初始化 /* 如果在虚基类中定义了带参数的构造函数...
  • C++虚基类作用

    2017-03-03 10:15:29
    当一个基类被声明为虚基类后,即使它成为了多继承链路上的公共基类,最后的派生类中也只有它的一个备份。例如: class CBase { }; class CDerive1:virtual public CBase{ }; class CDerive2:virtual public ...
  • C++ 虚基类的初始化

    千次阅读 2015-04-23 10:47:04
    如果一个派生类有多个基类,而这些直接基类又有一个共同的基类,则在最终的派生类中会保留该间接...对虚基类的派生类:在最后的派生类中不仅要负责对其直接基类进行初始化,还要对虚基类初始化。 代码一: #inclu
  • c++ 虚基类和虚函数+代码.有一个案例,里面有源代码。看完就懂什么叫c++ 虚基类和虚函数了
  • C++抽象基类与虚基类C++ primer)

    千次阅读 2019-05-02 15:18:35
    c++ primer plus P556,虚基类 抽象基类(abstract base class,ABC) 抽象基类是解决如下问题: 加入现在需要开发一个图形类,表示圆与椭圆(注意,圆是一种特殊的椭圆)。所以初步考虑从椭圆类中派生出圆类。但是...
  • 下面小编就为大家带来一篇详谈C++虚基类在派生类中的内存布局。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 72,640
精华内容 29,056
关键字:

c++虚基类

c++ 订阅