一、使用&特性
1.可在任何方法上添加virtual,例:virtual void play();
2.继承性:一旦基类中为虚函数,子类将不会为非虚函数
3.优缺性:声明虚方法除了使程序慢一点点以外,没有任何缺点
二、说说为什么要用虚方法
因为当我们使用基类的引用或指针调用基类中定义的某个函数时,我们并不知道该函数真正的对象是什么类型(属于哪个类),因为它可能是一个基类的对象,也可能是一个子类的对象
#include <iostream>
using namespace std;
class Base
{
public:
Base(int _x):x(_x)
{
}
virtual int get()
{
cout<<"Base的get"<<endl;
return x;
}
private:
int x;
};
class Derived:public Base
{
public:
Derived(int _y):Base(_y),y(_y)
{
}
int get()
{
cout<<"Derived的get"<<endl;
return y;
}
private:
int y;
};
int main()
{
Base *a=new Derived(5);
cout<<a->get()<<endl;
return 0;
}
由以上代码可以看出,在基类亦或是子类中都有get的方法
若基类中没有virtual声明,其结果为
若基类中含有virtual声明,其结果为
可以看出,若不调用虚方法,编译器在编译的时候a是Base类的指针,所以编译器就认为a指针调用的方法是Base类里的方法,因为这样的执行效率是最快的,原理也就是对非虚函数的调用在编译的时候进行了绑定,这和通过对象(不是指针或引用)进行的函数调用也在编译是绑定一样
但是若通过指针或引用调用虚方法时,就会在运行时解析该调用,即在编译时是Base类的指针,但在运行时才确定是指向Derived的方法的,也只有这种情况下,对象的动态类型才有可能与静态类型不同
- 所以这里我们显然要指向Derived的方法,所以必须要用virtual声明
- 所以总结得:对虚函数调用运行时才被解析,对非虚函数调用时编译时就被解析了
三、基类and子类覆盖类型匹配
一个子类的函数如果覆盖了某个继承而来的虚函数,则形参类型与基类中被覆盖的方法要完全一样(包括返回类型),若虚函数的返回类型是类本身的指针或引用时,它们的返回类型可以不匹配
所以若改变上述代码中基类的名字,其他不变,那么因为基类和子类名字不同会导致异常
错误提示
四、注意点
1.若拿不准要不要使某个方法为虚方法,就声明为虚方法,优缺点前面已经说了,出来使程序慢一点点以外没有其他缺点
2.最好在基类里把所有方法都声明为虚方法
3.在实现一个多层次的类继承关系时,最顶级的基类应该只要虚方法
4.所以析构器都是虚方法,从编译的角度看,它只是普通方法,但如果不是虚方法,编译器会绑定编译时的版本,这样可能会多次析构基类里的成员,这对于析构器来说绝对是不安全的,会导致内存泄漏
本文详细介绍了C++中虚函数的使用方法及特性,解释了为何需要使用虚函数,并通过实例演示了虚函数如何实现多态性。文章还讨论了基类与子类中虚函数覆盖的要求以及使用虚函数时需要注意的事项。
767

被折叠的 条评论
为什么被折叠?



