浅析c++中virtual关键字
来源:互联网 发布:淘宝视频代看怎么做 编辑:程序博客网 时间:2024/05/22 20:27
原文出自:http://blog.csdn.net/djh512/article/details/8973606#t4
1.virtual关键字主要是什么作用?
c++中的函数调用默认不适用动态绑定。要触发动态绑定,必须满足两个条件:第一,指定为虚函数;第二,通过基类类型的引用或指针调用。
由此可见,virtual主要主要是实现动态绑定。
2.那些情况下可以使用virtual关键字?
virtual可用来定义类函数和应用到虚继承。
友元函数 构造函数 static静态函数 不能用virtual关键字修饰;
普通成员函数 和析构函数 可以用virtual关键字修饰;
3.virtual函数的效果
class GrandFather { public: GrandFather() {} virtual void fun() { cout << "GrandFather call function!" << endl; } }; class Father : public GrandFather { public: Father() {} void fun() { cout << "Father call function!" << endl; } }; class Son : public Father { public: Son() {} void fun() { cout << "Son call function!" << endl; } }; void print(GrandFather* father) { father->fun(); } int _tmain(int argc, _TCHAR* argv[]) { Father * pfather = new Son; pfather->fun(); GrandFather * pgfather = new Father; print(pgfather); return 0; }
输出为 Son call function
Father call function
4.virtual的继承性
只要基函数定义了virtual,继承类的该函数也就具有virtual属性
即 GrandFather Father Son同时定义virtual void fun()与GrandFather一个定义virtual void fun效果是一样的
5.虚析构函数
class GrandFather { public: GrandFather() {} virtual void fun() { cout << "GrandFather call function!" << endl; } ~GrandFather() { cout << "GrandFather destruction!" << endl; } }; class Father : public GrandFather { public: Father() {} void fun() { cout << "Father call function!" << endl; } ~Father() { cout << "Father destruction!" << endl; } }; class Son : public Father { public: Son() {} void fun() { cout << "Son call function!" << endl; } ~Son() { cout << "Son destruction!" << endl; } }; void print(GrandFather* p) { p->fun(); } int _tmain(int argc, _TCHAR* argv[]) { Father * pfather = new Son; delete pfather; return 0; }
以上代码输出:Father destruction!
GrandFather destruction!
执行了Son的构造函数,没执行Son的析构函数,故把GrandFather的析构函数设置为virtual
则输出: Son destruction!
Father Destruction!
GrandFather destruction!
6. 纯虚函数
纯虚函数定义如下:
class GrandFather { public: GrandFather() {} virtual void fun() = 0 { cout << "GrandFather call function!" << endl; } virtual ~GrandFather() { cout << "GrandFather destruction!" << endl; } };
纯虚函数为后代类提供可覆盖的接口,但这个类中的版本决不会调用。
含有(或继续)一个或多个纯虚函数的类是抽象基类,抽象基类不能实例化!
继承类只有重写这个接口才能被实例化
7.虚继承
虚继承主要解决交叉继承带来的问题。这里给出一片参考文章c++虚继承。
给一个例子如下
class GrandFather { public: GrandFather() {} void fun() { cout << "GrandFather call function!" << endl; } virtual ~GrandFather() { cout << "GrandFather destruction!" << endl; } }; class Father1 : public GrandFather { public: Father1() {} void fun() { cout << "Father call function!" << endl; } }; class Father2 : public GrandFather { public: Father2() {} void fun() { cout << "Father call function!" << endl; } }; class Son : public Father1, public Father2 { public: Son() {} //void fun() //{ // cout << "Son call function!" << endl; //} }; void print(GrandFather* p) { p->fun(); } int _tmain(int argc, _TCHAR* argv[]) { Son* son = new Son; son->fun(); return 0; }
编译时会提示报错对fun的访问不明确
如果Father1和Father2都用虚继承继承GrandFather类则可以解决这个问题
8. 构造函数和析构函数中的虚函数
如果在构造函数或析构函数中调用虚函数,则运行的是为构造函数或析构函数自身类型定义的版本
9.虚函数的实现机制
关于虚函数的实现机制,这里给出一篇认为写得蛮清楚的文章。c++虚函数实现机制
10.小结
关于virtual关键字的用法总结如上,有错误或者总结不到位的情况请能帮本人指出!
11.例子
class classA { public: classA() { clear(); } virtual ~classA() { } void clear() { memset(this , 0 , sizeof(*this)); } virtual void func() { printf("func\n"); } }; class classB : public classA { }; int main(void) { classA oa; classB ob; classA * pa0 = &oa; classA * pa1 = &ob; classB * pb = &ob; oa.func(); // 1 ob.func(); // 2 pa0->func(); // 3 pa1->func(); // 4 pb->func(); // 5 return 0; }
补充一个例子,这个程序输出依次是
func
func
出错
func
func
谈谈我的理解,当
classA oa;
oa.func();
不存在动态调用的过程,所以func虽然是虚函数,但是函数调用不通过虚表访问,所以即使
memset(this , 0 , sizeof(*this));
找不到虚表地址也没有关系
在执行classB ob;的时候,注意memset的是classA的地址,所有ob的虚表是存在的
即是如下,通过指针或引用(动态绑定)访问oa的func函数(需要从虚表访问),会出错
访问ob的func和函数,无论静态访问还是动态访问,都不会出错
当把classB的代码改成如下时
class classB : public classA [cpp] view plaincopy<pre name="code" class="cpp" style="font-weight: bold;">{</pre><pre name="code" class="cpp" style="font-weight: bold;"> classB() { clear(); } virtual ~classB() { } void clear() { memset(this , 0 , sizeof(*this)); }
func
func
出错
出错
出错
0 0
- 浅析c++中virtual关键字
- 浅析c++中virtual关键字
- 浅析c++中virtual关键字
- 浅析c++中virtual关键字
- 浅析c++中virtual关键字
- 浅析c++中virtual关键字
- 浅析C#中new、override、virtual关键字的区别
- 浅析C#中new、override、virtual关键字的区别
- 浅析C#中new、override、virtual关键字的区别
- 浅析C#中new、override、virtual关键字的区别
- 浅析C#中new、override、virtual关键字的区别
- 浅析C#中new、override、virtual关键字的区别
- 浅析C#中new、override、virtual关键字的区别
- 浅析C#中new、override、virtual关键字的区别
- 浅析C#中new、override、virtual关键字的区别
- C# 关键字--virtual
- c++Virtual关键字
- C++:virtual关键字
- ANDROID 一键搞定JNI创建C头文件
- ForThirdWork-No.2:C/C++笔试题回忆并整理
- QT控件之按钮
- QT控件之数码管
- openfire xep-0055 设置
- 浅析c++中virtual关键字
- 另一种阶乘问题
- 深入了解HTML中表格的属性
- 2014-2-24 日记
- 分数拆分
- POJ 1003 Hangover - 搜索算法 - 二分查找法
- 存储过程概述
- wrapper 添加 jpda
- UVa 10112 Myacm三角形