C++虚函数
_拾贰_ 人气:0阐述虚函数作用和原理、纯虚函数和虚函数的区别。
一、虚函数
首先来看下面这一段代码,首先创建两个类,一个是Dog,另一个是Cat,他们有一个共同的属性:Run。在定义中每个动物都需要创建一个类,比较繁琐,所以在下面的例子中,我们可以把他们简化。
#include <iostream> using namespace std; class Dog{ public: void Run(){ cout<<"Dog->Run"<<endl; } }; class Cat{ public: void Run(){ cout<<"Cat->Run"<<endl; } }; int main() { Dog d; d.Run(); Cat c; c.Run(); return 0; }
这里使用多态和虚函数,而Animal提供统一的接口,供子类使用,虽然代码繁琐,但提高了整个工程的可扩展性和灵活性。
在普通函数前加上关键字 virtual 构成虚函数,子类需要重写父类的虚函数,这样在调用的时候,会覆盖掉父类的虚函数 Run,去执行子类的Run。
#include <iostream> using namespace std; class Animal{ public: virtual void Run(){ cout<<"Animal->Run"<<endl; } }; class Dog :public Animal{ public: void Run(){ cout<<"Dog->Run"<<endl; } }; class Cat:public Animal{ public: void Run(){ cout<<"Cat->Run"<<endl; } }; int main() { Animal *ani; ani = new Dog; ani->Run(); delete ani; ani = new Cat; ani->Run(); delete ani; return 0; }
结果如下:
所以在这里只需要修改ani的指向就可以实现不同方法。如果不存在虚函数,把Animal类的关键词virtual去掉会怎么样呢,显然,他们会默认实现父类Run的方法。
class Animal{ public: void Run(){ cout<<"Animal->Run"<<endl; } };
所以引入虚函数是为了实现动态多态,指向不同的子类来实现不同的方法。
二、虚函数与纯虚函数的区别
因为父类的函数可以不做任何操作,所以这里可以直接等于0;实现纯虚函数。
//虚函数 class Animal{ public: virtual void Run(){ cout<<"Animal->Run"<<endl; } };
//纯虚函数 class Animal{ public: virtual void Run()=0; };
虚函数与纯虚函数的区别:
纯虚函数只是一个接口,只能供子类去重写实现方法。而虚函数在里面也可以去实现父类的功能。只需要指向父类的方法即可。
总结:虚函数在子类里面也可以不进行重写,但纯虚函数必须在子类去实现,如果把子类中的Run方法去掉,只留下父类中的纯虚函数,那么编译器会报错,这里大家可以试试。
三、动态多态
Animal内部的结构是什么样呢?这里有一个虚函数指针(vfptr)和虚函数表(vftable)。 指针(vfptr)指向虚函数表,在虚函数表(vftable)内记录着虚函数的地址,即Run函数的地址。
当子类的Dog去继承父类后,父类的虚函数表相应的也继承下来,子类也会保存一份和父类相同的。
注意!这时候如果发生重写,即子类重写了父类的虚函数,则子类的虚函数表会覆盖父类继承下来的虚函数表。但父类的虚函数表不会发生改变。
当父类的指针或者引用指向子类的对象时,就发生了多态。
下面的代码中是指向了Dog,所以会去Dog的虚函数表中找到相应的函数,在运行阶段发生了动态多态。
Animal *ani; ani = new Dog; ani->Run();
加载全部内容