在C++中要想正确的重写方法,就必须使用virtula关键字,用来声明方法为虚的如果不声明为虚方法就会出现一些微妙的错误.例如:
class Super{
public :
void go(){cout << "super go" << endl;}
}
class Sub : class Super{
public :
void go(){cout << "sub go" << endl;}
}
如果对Sub调用go方法会打印sub go,但是由于不是声明为虚方法,当我们使用多态时,用Super的引用指向Sub的实现时,将得不到想要的结果
Sub mSub;
Super & mSuper = mSub;
mSuper.go();
得到的结果是super go,因为Sub的go和Super的go没有一点关系。但是如果将方法添加virtual后,将会得到sub go,这才是我们预期得到的结果.了解了virtual的作用后,还需要理解一下virtual的工作原理。
当我们将方法声明为virtual的时候会使用名为虚表(vtable)的特定内存区域调用正确的实现,每一个具有一个或者多个的方法都有一张虚表,这个类的每一个对象都会有一个指向虚表的指针,这个表包含了指向虚方法实现的指针,通过这样,当使用某个对象的方法时,指针也进入虚表,然后根据实际的对象调用正确的版本.
class Super{
virtual void fun1();
virtual void fun2();
void fun3();
}
class Sub{
virtual void fun1();
void fun3();
}
对应于的实现
Sub mySub;
Super mySuper;
由于方法fun3没有定义为virtual所以不会出现在虚表里面,Sub重写了fun1,所以mySub的虚表fun1指向了自己的实现,fun2没有重写,指向了mySuper的fun2的实现.
但是虚表也会有一定的开销,调用virtual方法也会执行附加操作,即对指向要执行的适当代码的指针解除引用。