虚函数和类的多态性
来源:互联网 发布:域名服务器ip地址 编辑:程序博客网 时间:2024/06/05 12:42
多态特性让程序员省去了细节的考虑,提高了开发效率,使代码大大的简化,当然虚函数的定义也是有缺陷的,因为多态特性增加了一些数据存储和执行指令的开销,所以能不用多态最好不用。(为了实现virtual函数,类中间必须要增加一个pointer指向虚函数表,这样增大了类的体积。所以没有必要的话,还是不要随意声明virtual的析构函数。普遍的规则是只有当类当中有virtual的函数时,析构函数才声明为virtual。也就是说这个基类是有多态性质(polymorphic)的)
虚函数的定义要遵循以下重要规则:
1.如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,那么即使加上了virtual关键字,也是不会进行滞后联编(即多态性late binding,重载叫先期联编early binding)的。
2.只有类的成员函数才能说明为虚函数,因为虚函数仅适合用与有继承关系的类对象,所以普通函数不能说明为虚函数。
3.静态成员函数不能是虚函数,因为静态成员函数的特点是不受限制于某个对象。
4.内联(inline)函数不能是虚函数,因为内联函数不能在运行中动态确定位置。即使虚函数在类的内部定义,但是在编译的时候系统仍然将它看做是非内联的。
5.构造函数不能是虚函数,因为构造的时候,对象还是一片未定型的空间,只有构造完成后,对象才是具体类的实例。
6.析构函数可以是虚函数,而且通常声名为虚函数。
说明一下,虽然我们说使用虚函数会降低效率,但是在处理器速度越来越快的今天,将一个类中的所有成员函数都定义成为virtual总是有好处的,它除了会增加一些额外的开销是没有其它坏处的,对于保证类的封装特性是有好处的。
1.典型的虚函数用法
可以看到,只有标识为virtual的函数才会产生多态的效果,而且是编译多态。它只能借助指针或者引用来达到多态的效果。
class A{public:virtual void f(){cout<<"A::f()";}//虚函数void g(){cout<<"A::g()";}//普通函数};class B :public A{public:virtual void f(){cout<<"B::f()";}void g(){cout<<"B::g()";}};class C :public A{public:virtual void f(){cout<<"C::f()";}void g(){cout<<"C::g()";}};int _tmain(int argc, _TCHAR* argv[]){A* pa=new B;//pa是指针喔pa->f(); // 调用B::f()pa->g(); // 调用A::g()delete pa;pa=new C;pa->f(); // 调用C::f()pa->g(); // 调用A::g()delete pa;pa=NULL;return 0;}
2.虚函数的默认继承
虚函数是默认继承virtual属性的,即使在子类中没有标识virtual。
class A{public:virtual void f(){cout<<"A::f()";}};class B :public A{public:void f(){cout<<"B::f()";}//不加virtual了};class C :public B{public:void f(){cout<<"C::f()";}//也不加virtual了};int _tmain(int argc, _TCHAR* argv[]){A* pa=new B;pa->f(); // 调用B:f()delete pa;pa=new C;pa->f(); // 调用C:f()delete pa;pa=NULL;return 0;}
3.纯虚函数
纯虚函数和Java中的接口很像了,因为纯虚函数的存在导致了该类成了抽象类,它的主要作用就是规范接口,把实现留给子类。如果子类没有实现它的所有虚函数,那么该子类也是一个抽象类,通用不能进行实例化。
class A{public:virtual void f()=0;//纯虚函数,导致该类为抽象类};class B :public A{public:virtual void f(){cout<<"B::f()";}};int _tmain(int argc, _TCHAR* argv[]){//A* pa=new A;//出错,不能实例化抽象类A* pa=new B;pa->f();//调用B::f()delete pa;pa=NULL;return 0;}
4.虚函数的调用模型
子类调用父类函数只有虚函数才得以执行,普通函数只会调用父类函数,不过要注意以下的h()可不能是构造函数或者析构函数,不然多态就无法实现。
class A{private:virtual void f(){cout<<"A::f()"<<endl;}void g(){cout<<"A::g()"<<endl;}public:void h(){f();g();}};class B :public A{private:virtual void f(){cout<<"B::f()"<<endl;}void g(){cout<<"B::g()"<<endl;}};int _tmain(int argc, _TCHAR* argv[]){B b;b.h();//调用父类的h(),分别再调用f()和g()。f()为虚函数调用子类B::f(),g()为普通函数调用父类A::g()。return 0;}
5.虚析构函数
虚构函数可以是虚函数,甚至是纯虚函数。如果它作为一个基类,那析构函数必须是虚函数。
而构造函数不能是虚函数。
class A{public: A(){p_a=new char[1];cout<<"new 1"<<endl;}virtual ~A(){delete[] p_a;cout<<"delete 1"<<endl;}//正常//~A(){delete[] p_a;cout<<"delete 1"<<endl;}//异常,内存泄漏,~B()并没有被执行到private:char* p_a;};class B :public A{public:B(){p_b=new char[2];cout<<"new 2"<<endl;}~B(){delete[] p_b;cout<<"delete 2"<<endl;}//能不能正确执行~B()成了关键private:char* p_b;};int _tmain(int argc, _TCHAR* argv[]){A* pa=new B;delete pa;return 0;}
- 虚函数和类的多态性
- 类的虚函数和多态性
- 多态性和虚函数
- 虚函数和多态性
- 虚函数和多态性
- 虚函数和多态性
- 多态性和虚函数
- 多态性和虚函数
- 多态性和虚函数
- 多态性和虚函数
- 多态性和虚函数
- 虚函数和多态性
- 多态性和虚函数
- 多态性和虚函数
- 多态性和虚函数
- 13.1 对虚函数、多态性和抽象类的理解
- 虚函数和多态性的简单认识
- 关于多态性和虚函数的理解
- mac Sublime Text 2 破解
- android BitmapFactory.Options 优化bitmap图像
- 菜单使用
- Linux中用C语言写系统日志
- 其实Unix很简单
- 虚函数和类的多态性
- 快速排序详解
- Decoding Java.Lang.OutOfMemoryError: PermGen Space
- 一些破事儿
- linux基础命令和知识(二)
- 五种常见的php设计模式
- 关于php中header()、setcookie()、session_start()函数错误的解决方法和解释
- iOS 推送
- 谈谈html转义字符