`
隐形的翅膀
  • 浏览: 482265 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

虚基类,虚函数,虚析构函数

 
阅读更多
继承的类的前面加上virtual关键字表示被继承的类是一个虚基类,它的被继承成员在派生类中只保留一个实例

class A
{
public:
    int iValue;
};

class B:public A
{
public:
    void bPrintf(){cout<<"This is class B"<<endl;};
};

class C:public A
{
public:
    void cPrintf(){cout<<"This is class C"<<endl;};
};

class D:public B,public C
{
public:
    void dPrintf(){cout<<"This is class D"<<endl;};
};

void main()
{
    D d;
    cout<<d.iValue<<endl; //错误,不明确的访问
    cout<<d.A::iValue<<endl; //正确
    cout<<d.B::iValue<<endl; //正确
    cout<<d.C::iValue<<endl; //正确
}

从代码中可以看出类B C都继承了类A的iValue成员,因此类B C都有一个成员变量iValue ,而类D又继承了B C,这样类D就有一个重名的成员 iValue(一个是从类B中继承过来的,一个是从类C中继承过来的).在主函数中调用d.iValue 因为类D有一个重名的成员iValue编译器不知道调用 从谁继承过来的iValue所以就产生的二义性的问题.正确的做法应该是加上作用域限定符 d.B::iValue 表示调用从B类继承过来的iValue。不过 类D的实例中就有多个iValue的实例,就会占用内存空间。所以C++中就引用了虚基类的概念,来解决这个问题。


class A
{
public:
    int iValue;
};

class B:virtual public A
{
public:
    void bPrintf(){cout<<"This is class B"<<endl;};
};

class C:virtual public A
{
public:
    void cPrintf(){cout<<"This is class C"<<endl;};
};

class D:public B,public C
{
public:
    void dPrintf(){cout<<"This is class D"<<endl;};
};

void main()
{
    D d;
    cout<<d.iValue<<endl; //正确
}

在继承的类的前面加上virtual关键字表示被继承的类是一个虚基类,它的被继承成员在派生类中只保留一个实例。例如iValue这个成员,从类 D这个角度上来看,它是从类B与类C继承过来的,而类B C又是从类A继承过来的,但它们只保留一个副本。因此在主函数中调用d.iValue时就不 会产生错误。 


声明指向类的指针时,不管引用的实例是哪个类的, 当你调用的时候系统会调用左值那个对象所属类的方法

class A
{
public:
    void funPrint(){cout<<"funPrint of class A"<<endl;};
};

class B:public A
{
public:
    void funPrint(){cout<<"funPrint of class B"<<endl;};
};

void main()
{
    A *p; //定义基类的指针
    A a;
    B b;
    p=&a;
    p->funPrint();
    p=&b;
    p->funPrint();
}
答案是funPrint of class A 与 funPrint of class A
因为p是一个A类的指针,所以不管你将p指针指向类A或是类B,最终调用的函数都是类A的funPrint 函数。这就是静态联篇,编译器在编译的时候就已经确定好了

如果我想实现跟据实例的不同来动态决定调用哪个函数呢?这就须要用到 虚函数(也就是动态联篇)

在基类的成员函数前加virtual关键字表示这个函数是一个虚函数,所谓虚函数就是在编译的时候不确定要调用哪个函数,而是动态决定将要调 用哪个函数,要实现虚函数必须派生类的函数名与基类相同,参数名参数类型等也要与基类相同。但派生类中的virtual关键字可以省略,也表 示这是一个虚函数

class A
{
public:
    virtual void funPrint(){cout<<"funPrint of class A"<<endl;};
};

class B:public A
{
public:
    virtual void funPrint(){cout<<"funPrint of class B"<<endl;};
};

void main()
{
    A *p; //定义基类的指针
    A a;
    B b;
    p=&a;
    p->funPrint();
    p=&b;
    p->funPrint();
}
funPrint of class A
funPrint of class B



用C++开发的时候,用来做基类的类的析构函数一般都是虚函数
这样做是为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。

并不是要把所有类的析构函数都写成虚函数。因为当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间。
所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数。

class ClxBase
{
public:
    ClxBase() {};
    virtual ~ClxBase() {};

    virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
};

class ClxDerived : public ClxBase
{
public:
    ClxDerived() {};
    ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; }; 

    void DoSomething() { cout << "Do something in class ClxDerived!" << endl; };
};



ClxBase *pTest = new ClxDerived;
pTest->DoSomething();
delete pTest;
分享到:
评论

相关推荐

    C++虚基类 虚函数 虚析构函数

    //析构函数做成员函数 }; Base::~Base()//成员函数实现 { cout; } class Derived:public Base { public: Derived(); ~Derived(); private: int *p; }; Derived::Derived() { p=new int(0);//从堆上分配一个int型...

    虚基类 虚函数成员 虚析构函数

    该资源的内容主要是 虚基类 虚函数成员 虚析构函数的具体的区别

    C++中基类的析构函数为什么要用virtual虚析构函数.pdf

    C++中基类的析构函数为什么要用virtual虚析构函数.pdf

    浅谈C++基类的析构函数为虚函数

     在实现多态时, 当用基类指针操作派生类, 在析构时候防止只析构基类而不析构派生类。 2、例子:  (1)、    #include  using namespace std;  class Base{  public: Base() {};  ~Base() {cout &lt;&...

    C++中虚析构函数的作用

    我们知道,用C++开发的时候,用来做基类的类的析构函数一般都是虚函数。可是,为什么要这样做呢?下面用一个小例子来说明:

    C++中确定基类有虚析构函数

    本文给大家介绍了C++中确定基类有虚析构函数的方法。

    C++虚析构函数、纯虚析构函数

     因为在C++中,当一个派生类对象通过使用一个基类指针删除,而这个基类有一个非虚的析构函数,则结果是未定义的。运行时比较有代表性的后果是对象的派生部分不会被销毁。然而,基类部分很可能已被销毁,这导致了一...

    C++ 课程作业 继承与派生 (motorcycle类设计(虚基类))

    定义一个motorcycle的对象,分别调用run()和stop(),观察构造/析构函数的调用情况。 注意:构造函数和析构函数中均为cout语句,说明哪个构造/析构函数被调用。 该题重点和难点在于构造函数的设计,需考虑怎么给基类及...

    多继承与虚基类

    1, 设计一个人员基类person类,包括描述基本信息的数据成员,提供基本操作的函数成员以及析构函数和不同形式的构造函数

    从汇编看c++的默认析构函数的使用详解

    c++中,如果没有为一个类提供析构函数,那么...2 类继承自一个基类,基类含有自定义析构函数(如果基类没有自定义析构函数,但是编译器会为它提供一个非无用的默认析构函数,也属于这种情况。这就是说,只要基类含有一

    c++思维导图/很全,附带考点

    2.用基类类型指针绑定派生类实例,析构的时候,如果基类析构函数不是虚函数,则只会析构基类,不会析构派生类对象,从而造成内存泄漏。 ●C++默认的析构函数不是虚函数是因为虚函数需要额外的虚函数表和虚表指针,...

    类的继承与派生实验

    1:掌握单继承和多继承下派生类的定义方法,理解基类成员在...3:理解同名冲突的产生原因,会使用虚基类来解决第三类同名冲突问题,并理解引入虚基类后构造函数、析构函数的调用顺序。 4:理解赋值兼容的相关使用方法。

    详解C++中虚析构函数的作用及其原理分析

    我们知道,用C++开发的时候,用来做基类的类的析构函数一般都是虚函数。可是,为什么要这样做呢?下面用一个小例子来说明: #include using namespace std; class ClxBase { public: ClxBase() {}; virtual ~C

    c++ 习题 派生类和继承

    派生类的构造函数是怎样的执行顺序,析构函数的执行顺序是如何实现的?什么是虚基类?它有什么作用?含有虚基类的派生类的构造函数有什么要求,什么是最远派生类,建立一个含有虚基类的派生类的对象时,为什么由最远...

    类中的函数分类与虚函数的原理

    析构函数:当[DELETE]类指针时 非虚会从[此类]一直释放到基类,为虚时会从被赋于的[NEW类]的析构函数一直释放到基类. 总得来说释放[方向]都是从[子类]到[父类],只是开始释放的位置不一样.这就是为什么基类的析构函数...

    c.c++找工作面试重点结构图-mindmanager

    一般构造函数,析构函数,重载运算符函数是不能直接继承,但是可以间接调用 构造顺序,父类构造,子类构造,析构顺序,子类析构,父类析构 面向对象中的继承指类的继承,类似父子继承 1、子类拥有父类的所有成员...

    C++虚函数和虚析构及标准C语言读取数值矩阵

    C++虚函数及其纯虚函数学习。...虚析构:基类必须用虚析构函数这样子类析构(消失灭亡)时候才会释放基类申请的空间。 标准C语言读取数值矩阵:标准C语言从txt读取数值,分隔符是逗号和空格。 具体代码使用方式如下。

    8-12腾讯二面答案.docx

    1.虚函数,多态实现,纯虚函数和虚函数区别,析构函数可以是虚函数吗,虚继承和虚基类。 2.STL:vector中reserve 和resize 区别 3.map和unordered_map区别 4.哈希表解决冲突的办法 5.多路io复用的机制 6.select和...

    C++中虚函数和纯虚函数定义

    因为虚函数的作用是允许在派生类中对基类的虚函数重新定义。所以虚函数只能用于类的继承层次结构中。  一个成员函数被声明为虚函数后,在同一类族中的类不能再定义一个非virtual的但与该虚函数具有相同的参数...

Global site tag (gtag.js) - Google Analytics