c++ virtual

来源:互联网 发布:mac qq远程桌面 编辑:程序博客网 时间:2024/06/14 04:50

virtual [ˈvɜ:rtʃuəl]  adj 虚拟的(计算机);这个单词很有必要强调下,对我这种,记性不好的人,一下是我碰到virtual的场合:

虚函数在C++中用于2种场合:2个函数都出自mac-low.h

1、在析构函数前面加virtual

class MacLowTransmissionListener

{

public:

MacLowTransmissionListener ();

        virtual ~MacLowTransmissionListener ();

};

2、在成员函数前面加virtual

virtualvoidGotCts (double snr,WifiMode txMode) = 0;

我们通过下面的例子来理解virtual在C++中的风采:

eg:

#include <iostream>
using namespace std;

class Base
{
public:
    Base(){cout<<"Base::constructor is called!"<<endl;}
    ~Base(){cout<<"Base::destructor is called!"<<endl;}//重点关注基类析构函数
    virtual void f(){cout<<"Base::f() is called!"<<endl;};
};

class Derived:public Base
//派生类

{
public:
    Derived(){cout<<"Derived::constructor is called!"<<endl;}
    ~Derived(){cout<<"Derived::destructor is called!"<<endl;}
    virtual void f(){cout<<"Derived::f() is called!"<<endl;}
};


int main()
{
    Base *pBase;
    pBase==new Derived();
    cout<<"*************************************"<<endl;
    pBase->f();
    cout<<"*************************************"<<endl;
    delete pBase;//delete表达式释放指针所指向的地址空间
//动态创建对象的默认初始化,new分配内存地址,new表达式创建Derived对象,并且返回此对象的地址,并且用该地址初始化指针pBase
    system("pause");
    return 0;
}

输出结果:

Base::constructor is called!

Derived::constructor is called!

*************************************

Derived::f() is called!

*************************************

Base::destructor is called!//调用了基类的析构函数

C++明确指出,当一个继承类经由一个基类的指针删除时,而该基类包含的是一个非虚析构函数,其结果是未定义的,所以上面的输出结果是错误的,原因是当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用,应该输出是

Derived::destructor is called!

Base::destructor is called!

分析:

1、基类的析构函数前面加上virtual,是为了避免删除析构函数时候,内存泄露;所以为了安全(实际执行时通常发生的是继承类的独有成分没有被销毁。这个后果很严重,会造成内存泄漏),基类中的析构函数必须为虚函数;

基类中的析构函数前面加virtual,当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间;

在Base类的析构函数~Base()前加上一个virtual就行了。这时通过基类指针删继承类会得到你期望的结果

class Base

{
public:
    Base(){cout<<"Base::constructor is called!"<<endl;}
    virtual ~Base(){cout<<"Base::destructor is called!"<<endl;}//大家关键是看这句
    virtual void f(){cout<<"Base::f() is called!"<<endl;};
};

再次输出结果:

Base::constructor is called!

Derived::constructor is called!

*************************************

Derived::f() is called!

*************************************

Derived::destructor is called!

Base::destructor is called!


注意:定义一个纯虚函数,是可以不带函数体;但是对于析构函数,纯虚析构函数,如果在基类中定义,必须带上函数体;即是我们也必须为这个函数提供一份实现;

class Base

{
public:
    Base(){cout<<"Base::constructor is called!"<<endl;}
    virtual ~Base()=0;//这里是会出现问题的,如果这个函数确实什么也不想做,
                    //那么至少定义为virtual ~Base()=0{}。
    virtual void f(){cout<<"Base::f() is called!"<<endl;};
};

2、成员函数前面加virtual,是为了实现多态;

是为了实现多态,也就是动态绑定,动态绑定的技术核心是虚函数表,在代码的编译阶段,虚函数表生成,

什么时候会执行函数的动态绑定?这需要符合以下三个条件。

  • 通过指针来调用函数
  • 指针upcast向上转型(继承类向基类的转换称为upcast,关于什么是upcast,可以参考本文的参考资料)
  • 调用的是虚函数





0 0
原创粉丝点击