您的位置:首页 > 编程语言 > C语言/C++

c++ virtual

2016-02-27 10:22 417 查看
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,可以参考本文的参考资料)
调用的是虚函数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: