虚函数原理及应用
来源:互联网 发布:网络维护考题 编辑:程序博客网 时间:2024/04/28 18:55
包含虚函数的类中隐含一个指针,叫做vptr(virtual table pointer,虚函数表指针)。 vptr 指向一个vtbl(virtual table,虚函数表)函数指针数组,该数组记录实际调用的函数地址。对于多继承的时候,情况稍微复杂一些。如果多个父类都包含虚函数,则类中vptr指针也会有多个。当子类对象实例赋值给父类时会对父类中的vptr进行初始化,使其指向含有实际访问的vtbl函数指针数组。
#include <iostream>using namespace std;class empty{};class base{public: virtual void f(){cout<<"base, virtual function f()"<<endl;}};class derived: public base{public: virtual void f1(){cout<<"derived, virtual function f1()"<<endl;}};int main(void){ base b; base *pb; derived *pd; void (* pf)(void); pd = new derived(); cout<<"size of empty class: "<<sizeof(empty)<<endl; cout<<"size of base class: "<<sizeof(base)<<endl; cout<<"size of derived class: "<<sizeof(derived)<<endl; cout<<"base vptr address: "<<(int *)(&b)<<endl; cout<<"function address in base: "<<(int *)*(int *)(&b)<<endl; pf = (void (*)()) * ((int *)*(int *)(&b)); (*pf)(); pf(); return 0;}yongmi@yongmi-hn:~/c$ g++ virtual_class.cpp yongmi@yongmi-hn:~/c$ ./a.out size of empty class: 1size of base class: 4size of derived class: 4base vptr address: 0xbfc30f50function address in base: 0x8048c18base, virtual function f()base, virtual function f()
空类的大小为1(每个类实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址),包含虚函数的类大小为4(隐含一个vptr指针)。
关系如下所示:
vptr---->base:f
(int *)(&b)是vptr的地址,存放的内容为*(int *)(&b),即vtbl数组地址。
(int *)*(int *)(&b),将vptr地址中的内容转换为int型指针,即vtbl数组中保存的值转换为int型指针。
(void (*)()) * ((int *)*(int *)(&b)),vtbl数组中保存的指针值转换为函数指针。
上面这个实例中可以看出,通过获取vptr可以通过函数指针来访问类中的成员函数(即使该成员函数为私有也能访问),这一点有违类的访问控制权限。
C++父类的析构函数应该使用虚函数,否则可能会造成内存泄漏。看下面这个例子:
#include <iostream>using namespace std;class base{public: ~base () { cout << "base, ~base()" << endl; }};class derived:public base{private: char *name;public: derived () { name = new char[10]; } virtual ~derived () { delete []name; cout << "derived, ~derived()" << endl; }};int main (void){ derived d; base *pb = new derived (); delete pb;} yongmi@yongmi-hn:~/c$ g++ virtual_constructor.cppyongmi@yongmi-hn:~/c$ ./a.out base, ~base()derived, ~derived()base, ~base()
运行结果显示,类derived的析构函数只调用了一次,造成子类中申请的内存泄漏。将程序修改之后如下:
#include <iostream>using namespace std;class base{public: virtual ~base () { cout << "base, ~base()" << endl; }};class derived:public base{private: char *name;public: derived () { name = new char[10]; } virtual ~derived () { delete []name; cout << "derived, ~derived()" << endl; }};int main (void){ derived d; base *pb = new derived (); delete pb;} yongmi@yongmi-hn:~/c$ g++ virtual_constructor.cppyongmi@yongmi-hn:~/c$ ./a.out derived, ~derived()base, ~base()derived, ~derived()base, ~base()
此时程序调用了类derived两次析构函数,没有造成内存泄漏。
原因是因为将子类对象赋给父类时,如果子类对象动态申请了内存空间,而父类析构函数不是虚函数时,子类的析构函数不能调用,所以无法释放内存空间。
参考资料:
C++ 虚函数表解析
C++中虚函数工作原理和(虚)继承类的内存占用大小计算
C++虚函数的原理
C++中基类的析构函数为什么要用virtual虚析构函数
- 虚函数原理及应用
- 虚函数的的原理及应用
- 虚函数的的原理及应用
- 虚函数原理与应用
- ftok函数 应用,原理及 shell 脚本实现
- 不定参数函数的原理及应用(转)
- 数据库原理及应用
- 数据库原理及应用
- 数据库原理及应用
- NAT原理及应用
- Ajax原理及应用
- MEPG2原理及应用
- Ajax原理及应用
- FFT原理及应用
- COM原理及应用
- LPC11C14GPIO原理及应用
- LPC11C14GPIO原理及应用
- ping原理及应用
- ubuntu 初体验
- 通过引用 调用数组形参
- DIV与SPAN之间有什么区别 http://www.cnblogs.com/windows/articles/1605631.html
- 别再孩子了-李开复
- 苹果退居次席三星成最大智能移动设备商
- 虚函数原理及应用
- Get rid of all @Override errors in Eclipse
- 小米手机2连接在UBUNTU12.04下调试
- jquery博客分享一些php常用代码(五)
- Javascript 二分法解方程 求量杯的高度
- mongodb的Multikey Indexes
- 数字图像去噪典型算法及matlab实现
- html textarea标签必须成对出现
- css 命名规范及浏览器bug处理