精华内容
下载资源
问答
  • c++继承之虚基类

    千次阅读 2015-03-11 20:56:59
    则这个公共基类会在多继承派生类的对象中产生多个公共基类子对象,如果要使这个公共基类再多继承派生类中只产生一个基类子对象,则需要将这个基类设置为虚拟基类,简称虚基类。  引进虚基类目的是为了解决二义性...

           虚基类的概念:

           若在多继承派生类中继承的基类再拥有一个公共基类,则这个公共基类会在多继承派生类的对象中产生多个公共基类子对象,如果要使这个公共基类再多继承派生类中只产生一个基类子对象,则需要将这个基类设置为虚拟基类,简称虚基类。

            引进虚基类的目的是为了解决二义性问题,使得公共基类再它的派生类对象中只产生一个基类子对象。

            虚基类说明格式为:

            virtual    <继承方式>   <基类名>

            virtual是说明虚基类的关键字,虚基类说明用在定义派生类时,卸载派生类名的后面。

            分析下面的程序:

    <span style="font-size:18px;">class A//多继承派生类D的虚基类 
    {
    public:
    	void f();
    private:
    	int a;
    };
    class B:virtual class A
    {
    protected:
    	int b;
    };
    class C:virtual class A
    {
    protected:
    	int c;
    };
    class D:public class B,public class C//多继承派生类D
    {
    public:
    	int g();
    private:
    	int d;
    };</span>


               程序分析:

             1,定义一个派生类D的对象d,则d.f(); 的形式是合法的。

             2,定义void  D::g()

                          {    f();   }   也是合法的。

             3,定义A *pd ;   pd=&d;    也是合法的。

             引进虚基类后,派生类中只存在一个虚基类的子对象。当一个类有虚基类时,编译系统将为该类的对象生成一个指向虚基类的子对象的指针,该指针称为虚基类指针。

            虚基类及派生类的构造函数

            C++语言规定,虚基类子对象是由最远派生类的构造函数通过调用虚基类的构造函数进行初始化的。最远派生类是指在多层次的继承结构中,创建对象所指定的类。如果一个派生类有一个直接或间接的虚基类,则派生类的构造函数的成员初始化列表中必须包含对虚基类构造函数的调用。如果未列出,则表示该虚基类的默认构造函数来初始化派生类派生类对象中的虚基类子对象。为了保证虚基类子对象只被初始化一次,规定在创建对象的最远派生类的构造函数中调用虚基类的构造函数,而该派生类的基类构造函数中忽略对虚基类构造函数的调用。

           C++语言有规定,在派生类构造函数的成员初始化列表中,出现虚基类构造函数先于非基类构造函数的调用。

    <span style="font-size:18px;">#include <iostream>
    using namespace std;
    class A
    {
    public:
    	A(const char *s)
    	{ cout<<s<<endl; }
    };
    class B:virtual public A
    {
    public:
    	B(const char *s1,const char *s2):A(s1)
    	{
    		cout<<s2<<endl;
    	}
    };
    class C:virtual public A
    {
    public:
    	C(const char *s1,const char *s2):A(s1)
    	{
    		cout<<s2<<endl;
    	}
    };
    class D:public B,public C
    {
    public:
    	D(const char *s1,const char *s2,const char *s3,
    		const char *s4):B(s1,s2),C(s1,s3),A(s1)//多继承派生类D的构造函数
    	{ cout<<s4<<endl; }
    };
    int main()
    {
    	D *ptr=new D("class A","class B","class C","class D");//多继承派生D的对象
    	delete ptr;
    	return 0;
    }</span>

              程序分析:在派生类B和C中使用了虚基类A,使得派生类D的对象中只有一个基类A的子对象。输出的结果为:class A class B class C class D

      


     

            

    展开全文
  • 虚基类 的作用

    千次阅读 2018-06-02 11:13:02
    虚基类需要解决的问题当派生类从多个基类派生,而这些基类又共同基类,则在访问此共同基类中的成员时,将产生冗余,并有可能因冗余带来不一致性虚基类声明以virtual说明基类继承方式例:class B1:virtual public B...

    虚基类

    • 需要解决的问题
      • 当派生类从多个基类派生,而这些基类又共同基类,则在访问此共同基类中的成员时,将产生冗余,并有可能因冗余带来不一致性
    • 虚基类声明
      • 以virtual说明基类继承方式
      • 例:class B1:virtual public B
    • 作用
      • 主要用来解决多继承时可能发生的对同一基类继承多次而产生的二义性问题
      • 为最远的派生类提供唯一的基类成员,而不重复产生多次复制
    • 注意:
      • 在第一级继承时就要将共同基类设计为虚基类。

    虚基类举例

    #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 {
    //定义派生类Derived 
    public: 
        int var;
        void fun() {
            cout << "Member of Derived" << endl;
        }
    };
    
    int main() {    
        Derived d;
        d.var0 = 2; //直接访问虚基类的数据成员
        d.fun0();     //直接访问虚基类的函数成员
        return 0;
    }

    虚基类及其派生类构造函数

    • 建立对象时所指定的类称为最远派生类
    • 虚基类的成员是由最远派生类的构造函数通过调用虚基类的构造函数进行初始化的。
    • 整个继承结构中,直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化表中为虚基类的构造函数列出参数。如果未列出,则表示调用该虚基类的默认构造函数。
    • 在建立对象时,只有最远派生类的构造函数调用虚基类的构造函数,其他类对虚基类构造函数的调用被忽略。
      #include <iostream>
      using namespace std;
      
      class Base0 {   
      public:
          Base0(int var) : var0(var) { }
          int var0;
          void fun0() { cout << "Member of Base0" << endl; }
      };
      class Base1: virtual public Base0 {
      public: 
          Base1(int var) : Base0(var) { }
          int var1;
      };
      class Base2: virtual public Base0 { 
      public:
          Base2(int var) : Base0(var) { }
          int var2;
      };
      
      class Derived: public Base1, public Base2 {
      public:
          Derived(int var) : Base0(var), Base1(var), Base2(var) 
         { }
          int var;
          void fun() 
         { cout << "Member of Derived" << endl; }
      };
      
      int main() {    //程序主函数
          Derived d(1);
          d.var0 = 2; //直接访问虚基类的数据成员
          d.fun0();   //直接访问虚基类的函数成员
          return 0;
      }


    展开全文
  • 虚函数与虚基类

    2017-10-30 10:00:36
    3.虚基类是用来在多继承中,如果父类继承自同一个父类,就只实例化一个父类(说的有点绕,就是只实例化一个爷爷的意思=。=)。 为了记住以上区别,首先,需要明白为什么要引入虚函数,虚函数的作用是什么,有什

    1.虚函数是用于多态中virtual修饰父类函数,确保父类指针调用子类对象时,运行子类函数的。

    2.纯虚函数是用来定义接口的,也就是基类中定义一个纯虚函数,基类不用实现,让子类来实现。

    3.虚基类是用来在多继承中,如果父类继承自同一个父类,就只实例化一个父类(说的有点绕,就是只实例化一个爷爷的意思=。=)。

    为了记住以上区别,首先,需要明白为什么要引入虚函数,虚函数的作用是什么,有什么优势。(可参考:http://blog.csdn.net/huangyimo/article/details/50480313

    指针的灵活性,能实现多态重载。一个指针可以通过改变其指向的对象输出其与基类中相同的函数。相当于坐上一辆车后,你想到达不同地点只要告诉司机目的地就可以了。

    总结 :1、虚函数

    通过虚函数,在调用不同的衍生类的时候,可以拥有不同的功能。同时,我们可以通过将每个继承类都重写命名一个函数来替代也可以,这么做完全可以,只要你自己能熟记或者找到这个重命名函数是干嘛用的;但是在大一点的项目中,由于类中的函数成百上千,恐怕你就会为此疯狂。

    虚基类:派生类多继承的,具有公共基类的基类。理解几条道路的汇合点。


    纯虚函数:基类的虚函数是不用定义的,留给子类去实现。

    当函数没有实现方法或者需要子类来定义实现方法的时候,可以在父类中定义纯虚函数。就是这么简单!于是当不同的子类继承这个父类的时候,定义不同的实现方法,那么实例化这个子类的时候,这个纯虚函数就有了不同的方法。这也解释了为什么包含纯虚函数的抽象类为什么不能实例化,因为它中间有函数根本不知道是怎么个实现!当然我们可以用其他方法避免使用纯虚函数,比方说在子类中重写print方法,但是这样一来等于除了order函数代码以外所有的代码都要重新复制一遍,当继承类越来越多的时候,要修改print等于这一堆继承类都要修改,会疯的!所以说纯虚函数是一个很神奇的用法,也是简化了编程使得面向对象的方法更加灵活。

    参考:http://blog.csdn.net/huangyimo/article/details/50480313

    2.纯虚函数(pure virtual)

      C++中包含纯虚函数的类,被称为是“抽象类”。抽象类不能使用new出对象,只有实现了这个纯虚函数的子类才能new出对象。

      C++中的纯虚函数更像是“只提供申明,没有实现”,是对子类的约束,是“接口继承”。

      C++中的纯虚函数也是一种“运行时多态”。


    
    展开全文
  • 也可以将共同基类设置虚基类,这时从不同的路径继承过来的同名数据成员在内存中就只用一个拷贝,同一个函数名也只有一个映射。 二、虚基类的声明 语法形式: class 派生类名:virtual 继承方式 基类名 ...
    • 解释某个函数,我通常的讲解不会先去长篇大论去空谈,先整个例子来看看!!走起....
    #include <iostream>
    #include <string>
    using namespace std;
    
    class A
    {
    public:
        A(const char*s)
        {
            cout<<s<<endl;
        }
    };
    class B:virtual public A
    {
    public:
        B(const char*s1,const char*s2):A(s1)
        {
            cout <<s2<<endl;
        }
    };
    
    class C:virtual public A
    {
    public:
        C(const char*s1,const char*s2):A(s1)
        {
            cout<<s2<<endl;
        }
    };
    
    class D:public B,C
    {
    public:
        D(const char *s1,const char *s2,const char*s3,const char*s4):B(s1,s2),C(s1,s3),A(s1)
        {
            cout <<s4<<endl;
        }
    };
    int main(int argc, char* argv[])
    {
        D *ptr = new D("class A","class B","class C","class D");
        delete ptr;
        ptr = NULL;
        return 0;
    }

    先不要忙着去执行代码!!

    来看几个基本概念:

    一、虚基类的作用:

    当一个类的部分或者全部基类来自另一个共同的基类时,这些直接基类中从上一级共同基类继承来的  就拥有相同的名称。在派生类的对象中,这些同名数据成员在内存中同时拥有多个拷贝,同一个函数名会有多个映射。我们可以使用作用域分蝙蝠来唯一标识并分别访问他们, 也可以将共同基类设置为虚基类,这时从不同的路径继承过来的同名数据成员在内存中就只用一个拷贝,同一个函数名也只有一个映射。

    二、虚基类的声明  语法形式:

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

    三、使用虚基类时应该注意:

    1>一个类可以在一个类族中用作虚基类,也可以用作非虚基类。

    2>在派生类的对象中,同名的虚基类只产生一个虚基类子对象,而某个非虚基类产生各自的对象。

    3>虚基类子对象是由最派生类(最后派生出来的类)的构造函数通过调用虚基类的构造函数进行初始化。

    4>最派生类是指在继承类结构中建立对象时所指定的类。

    5>在派生类的构造函数的成员初始化列表中,必须列出对虚基类构造函数的调用,如果没有列出,则表示使用该虚基类的缺省构造函数。

    6>在虚基类直接或间接派生的派生类中的构造函数的成员初始化列表中,都要列出对虚基类构造函数的调用。但只有用于建立对象的最派生类的构造函数调用虚基类的构造函数,而该派生类的所有基类中列出的对虚基类构造函数的调用在执行中被忽略,从而保证对虚基类子对象只初始化一次。

    7>在一个成员初始化列表中,同时出现对虚基类和非虚基类构造函数的调用时,基类的构造函数先于非虚基类的构造函数执行。

    8>虚基类并不是在声明基类时声明的,而是在声明派生类是,指定继承方式时声明的。因为一个基类可以在生成一个派生类作为虚基类,而在生成另一个派生类时不作为虚基类。

    温馨提示:使用多重继承时要十分小心,经常会出现二义性。许多专业人员认为:不要提倡在程序中使用多重继承,只有在比较简单和不易出现二义性的情况或是在必要时才使用多重继承,能用单一继承解决的问题就不要使用多重继承,也是由于这个原因,有些面向对象的程序设计语言,并不支持多重继承。

    现在对虚基类构造函数了解了没??如果还不了解那么咱们就继续深入研究.....

    首先,要知道虚拟继承与普通继承的区别:

    假设derived继承自base类,那么derived与base是一种“is a”的关系,即derived类是base类,而反之错误;

    假设derived虚继承自base类,那么derived与base是一种“has a”的关系,即derived类有一个指向base类的vptr。

    因此虚继承可以认为不是一种继承关系,而可以认为是一种组合的关系。因为虚继承有着“继承”两个关键字,那么大部分人都认为虚继承与普通继承的用法没有什么太大的不同,由此用在继承体系中,这种将虚继承认为是普通继承的危害更加大!先用一个例子来说明问题:

    #include <iostream>
    using namespace std;
    
    class base
    {
    public:
        base()
        {
            cout <<"base::base()!"<<endl;
        }
        void printBase()
        {
            cout<<"base::printBase()!"<<endl;
        }
    };
    
    class derived:public base
    {
    public:
        derived()
        {
            cout<<"derived::derived()!"<<endl;
        }
        void printDerived()
        {
            cout<<"derived::printDerived()!"<<endl;
        }
    };
    
    int main(int argc, char* argv[])
    {
    
        derived oo;
        base oo1(static_cast<base>(oo));
    
        oo1.printBase();
    
        cout <<"---------------------"<<endl;
        derived oo2= static_cast<derived&>(oo1);
        oo2.printDerived();
    }

    运行结果:

    对前面的例子稍加修改......................

    #include <iostream>
    using namespace std;
    
    class base1
    {
    public:
        base1()
        {
            cout<<"base::base()!"<<endl;
        }
        void printBase()
        {
            cout<<"base::printBase()!"<<endl;
        }
    };
    class derived1:virtual public base1
    {
    public:
        derived1()
        {
            cout<<"derived::derived()!"<<endl;
        }
        void printDerived()
        {
            cout <<"derived::printDerived()!"<<endl ;
        }
    
    };
    
    int main(int argc, char* argv[])
    {
        derived1 oo;
        base1 oo1(static_cast<base1>(oo));
        oo1.printBase();
        
        derived1 oo2 = static_cast<derived1&>(oo1);
        oo2.printDerived();
        return 0;
    }

     

    会发现编译错误:error C2635: cannot convert a 'base1*' to a 'derived1*'; conversion from a virtual base class is implied(代码中红色部分出错)

    可以看到不能将基类通过static_cast转换为继承类。我们知道c++提供的强制转换函数static_cast对于继承体系中的类对象的转换一般是可行的。那么这里为什么不可以呢??

    virtual base class的原始模型是在class object中为每一个有关联的virtual base class加上一个指针vptr,该指针指向virtual基类表。有的编译器是在继承类已存在的virtual table直接扩充导入一个virtual base class table。不管怎么样由于虚继承已完全破坏了继承体系,不能按照平常的继承体系来进行类型转换。

     

    • 我们清楚了虚基类构造函数是怎么回事,那么接下来讲解一下 虚基类构造函数调用顺序 !!

    我们下来了解虚拟继承中遇到最广泛的菱形结构:

    #include <iostream>
    using namespace std;
    
    class stream
    {
    public:
        stream()
        {
            cout <<"stream::stream()!"<<endl;
        }
    };
    
    
    class iistream:virtual stream
    {
    public:
        iistream()
        {
            cout <<"istream::istream()!"<<endl;
        }
    };
    
    class oostream:virtual stream
    {
    public:
        oostream()
        {
            cout <<"ostream::ostream()!"<<endl;
        }
    };
    
    class iiostream:public iistream,oostream
    {
    public:
        iiostream()
        {
            cout<<"iiostream::iiostream()!"<<endl;
        }
    };
    
    int main(int argc, char* argv[])
    {
        iiostream oo;
        return 0;
    }

     

    运行结果:

    本来虚拟继承的目的就是当多重继承出现重复的基类时,其只保存一份基类,减少内存开销。

     

    这样子的菱形结构,使公共基类只产生一个拷贝。

    从基类stream派生新类时,使用virtual将类stream说明为虚基类,这时派生类istream、ostream包含一个指向虚基类的vptr,而不会产生实际的stream空间。所以最终iiostream也含有一个指向虚基类的vptr,调用stream中的成员方法时,通过vptr去调用,不会产生二义性!

    现在我们换种方式使用虚继承:

    #include <iostream>
    using namespace std;
    
    class stream
    {
    public:
        stream()
        {
            cout <<"stream::stream()!"<<endl;
        }
    };
    
    
    class iistream:public stream
    {
    public:
        iistream()
        {
            cout <<"istream::istream()!"<<endl;
        }
    };
    
    class oostream:public stream
    {
    public:
        oostream()
        {
            cout <<"ostream::ostream()!"<<endl;
        }
    };
    
    class iiostream:virtual iistream,oostream
    {
    public:
        iiostream()
        {
            cout<<"iiostream::iiostream()!"<<endl;
        }
    };
    
    int main(int argc, char* argv[])
    {
        iiostream oo;
        return 0;
    }

    运行结果:

    从结果上可以看到,其构造过程中重复出现基类的stream的构造过程,这样就完全没有达到虚拟继承的目的。其继承结构为:

    从继承结构可以看出,如果iiostream对象调用基类stream重的成员方法,会导致方法的二义性。因为iiostream含有指向其虚继承基类istream,ostream的vptr。而istream,ostream包含了stream的空间,所以导致iiostream不知道导致时调用那个stream的方法。要解决该问题,即在调用成员方法时需要加上作用域!

    转载自:http://blog.csdn.net/wzjking0929/article/details/51931204

    展开全文
  • 1.Cpp中的虚继承与虚基类 在多继承时,很容易产生命名冲突的问题,即使我们很小心地将所有类中的成员变量和成员函数都命名为不同的名字,命名冲突依然有可能发生,比如典型的是菱形继承,如下图所示: 类A派生出类...
  • 继承和派生、虚继承和虚基类虚基类表和虚基类指针继承和派生继承概述继承基本概念派生类中的成员继承的内容派生类定义派生类访问控制对象构造和析构对象构造和析构的调用顺序继承中的构造和析构的调用规则调用子类...
  • 2.理解虚基类的作用。 3.熟悉派生类对象与基类的转换。 实验要求 1.将代码和运行结果复制到word文档提交。 2.word文档命名格式:实验X-姓名-学号。 3.禁止抄袭。 4.按时提交。 实验内容 1.从Person类派生出学生类...
  • C++虚继承和虚基类;虚函数与继承

    千次阅读 2017-03-28 23:05:29
    定义:在C++中,在定义公共基类的派生类的时候,如果在继承方式前使用关键字virtual
  • 多继承(Multiple Inheritance)是指从多个直接基类中产生派生类的能力,多继承的派生类继承了所有父类的成员。尽管概念上非常简单,但是多个基类的相互交织可能会带来错综复杂的设计问题,命名冲突就是不可回避的一...
  • 1,虚继承的目的:解决环形多继承命名冲突导致的访问变量二义性问题,同时节省了内存 ...3,A为虚基类,B虚继承A时,A会产生一份虚基类表,表中记录了变量a与类B开始位置的偏移量, C虚继承A时, ...
  • C++虚基类与虚继承

    2018-05-24 22:58:16
    为什么有继承多继承(Multiple Inheritance)是指从多个直接基类中产生派生类的能力,多继承的派生类继承了所有父类的成员。尽管概念上非常简单,但是多个基类的相互交织可能会带来错综复杂的设计问题,命名冲突...
  • 虚基类和虚拟继承多重继承虚继承内存分布 多重继承 多继承(Multiple Inheritance)是指从多个直接基类中产生派生类的能力,多继承的派生类继承了所有父类的成员。尽管概念上非常简单,但是多个基类的相互交织可能会...
  • 多继承:是指从多个直接基类中产生派生类的能力,多继承的派生类继承了所有父类的成员。尽管概念上非常简单,但是多个基类的相互交织可能会带来错综复杂的设计问题,命名冲突就是不可回避的一个。 多继承时很容易...
  • 虚基类与虚继承

    2015-09-04 13:25:11
    引入虚基类目的是为了解决类继承过程中产生的二义性问题;这种二义性问题常见于具有菱形继承关系的类中; 比如:有四个类:A、B、C、D;它们之间的继承关系是:B继承A,C继承A,D继承B和C;这就形成了一个菱形的继承关系;...
  • c++中的虚函数、虚基类、类模板

    千次阅读 2016-08-15 14:17:37
    函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。 从以上的定义来看,需函数简单的说就是为了让基类指针能够指向派生类中与基类同名的函数而...
  • 4、在使用虚基类的情况下,构造父类的顺序问题 1、来自不同父类的相同成员的访问问题 多继承情况下,来自不同父类的相同成员的访问问题 :假设子类继承自2个父类,这两个父类中包含有同名的(数据)成员n,这时...
  • 为什么这里会出现vbptr,因为虚基类派生出来的类中,虚基类的对象不在固定位置(猜测应该是在内存的尾部),需 要一个中介才能访问虚基类的对象.所以虽然没有virtual函数,子类也需要有一个vbptr,对应的vtable中需要有一项...
  • C++的多态包括静态多态和动态多态,静态多态包括函数重载和泛型编程,动态多态包括函数。静态多态实在编译期间就能确定,动态多态实直在程序运行时才能确定。 抽象类 函数 在默认情况下对函数成员调用实施的是...
  • /**********************************...class 派生类名: 访问控制符 基类名1,访问控制符 基类名2 { 数据成员和成员函数声明; } class A: public B,public c { } 多个直接基类构造函数执行顺序取决于定义派生...
  • 2.理解虚基类的作用。 3.熟悉派生类对象与基类的转换。 二、具体内容 1.从Person类派生出学生类Student和教师类Teacher;从Student类中派生研究生类Graduate;从Graduate类和Teacher类派生出助教生类Assistant。根据...
  • 纯虚函数与虚基类

    千次阅读 2015-02-06 22:08:15
    纯虚函数是在基类中声明的函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0” virtual void funtion()=0; 函数的定义是:virtual void ...
  • 虚基类的内容

    2021-05-18 20:28:33
    当派生类从多个基类派生,而这些基类又从同一个基类派生,则在访问此共同基类中的成员时,将产生二义性——采用虚基类来解决。 解决方法一:用类名来限定 c1.A::f() 或 c1.B::f() 解决方法二:同名隐藏 ​ 在C 中...
  • 7-14 A是A1的虚基类 (10 分) 本题目要求读入3个整数A、B和C,然后按照下列要求完成相关设计:1.定义一个基类A,在其中包含保护的数据成员int i,设计类A的带参构造函数对i进行初始化,定义成员函数display()显示i...
  • 6.虚基类 1.虚函数的引入 先看如下程序,程序后有进一步的解释。如果读者对程序不懂请先复习基础知识。 // // VirtualFun.cpp // virtual // // Created by 刘一丁 on 2019/8/26. // Copyright © 2019年 ...
  • 当某类的部分或全部直接基类是从另...也可以将共同基类设置虚基类,这时从不同的路径继承过来的同名数据成员在内存中只拥有一个拷贝,同一个函数名也只有一个映射。也就是说虚基类解决了同名成员的唯一标识问题。 ...
  • C++虚基类的内存布局(上)

    千次阅读 2016-05-15 20:47:53
    最好看一下前一篇的C++函数表 简而言之,我们一个类可能会有如下的影响因素: 1)成员变量 2)函数(产生函数表) 3)单一继承(只继承于一个类) 4)多重继承(继承多个类) 5)重复继承(继承的多个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 30,232
精华内容 12,092
关键字:

设置虚基类的目的