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,可以参考本文的参考资料)
调用的是虚函数
虚函数在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,可以参考本文的参考资料)
调用的是虚函数
相关文章推荐
- C语言书籍推荐
- C++中的namespace
- C语言之基本算法09—各位全是a的数列之和
- C++笔记:1
- C++开发人脸性别识别教程(15)——搭建MFC框架启动摄像头
- 【C++】Accessor and Mutator Functions & 函数形参与类私有成员重名的解决方法
- Boost MPI scatter
- C++ DirectX 游戏开发初级视频教程 20 资源下载链接
- c++11对多线程的典型用法
- C++基础——1.变量和基本类型(基于c++11)
- C++模板板块
- C++ 2杈树 完整
- C++ 红黑树
- C++ 酒桶算法
- C++常用集合开发:STL vector
- C++ 造房子list
- C++ string 用法详解
- iOS开发系列--C语言之指针
- 图书信息借阅管理系统 C语言
- C++ 面向对象写汉罗塔游戏(作风::懒)