
我们知道,想要构成多态,必须使用虚函数,借助于虚函数表来实现,我们也知道,虚函数表是为了让父类引用子函数对象实现多态的,但是,为什么必须使用这种方式呢,来看一个有意思的例子
class Car
{
public:
int a=0;
void show(){
cout<<"this is virtual Car"<<a<<endl;
}
};
class miniCar: public Car
{
public:
int a=20;
void show()
{
cout<<"this is miniCar"<<a<<endl;
}
};
Car c1;
miniCar mc1;
c1 = mc1;
cout<<c1.a<<endl;
//我们知道,子类对象是可以转换为父类对象的,包括直接赋值、引用和指针,后两者都是对地址进行 *** 作
以上输出结果是多少呢,会是20吗???接着往下看吧
答案是0;
为什么?仔细考虑一下,子类中是不是包含了两个重名的属性a,一个是Car::a,一个是mini Car::a,是的,mini Car::a是为20,但是我们并没有对Car::a进行改变,而子类赋值给父类对象的时候,只会把原本就属于父类的属性赋值回去,也就是Car::a,但是,我们可并没有改变Car::a的值呀,再看以下代码你就明白了
//为miniCar写一个构造函数如下
miniCar()
{
Car::a=20;
}
可以验证一下,加上这段代码之后,输出结果就变成了20了,所以一定需要注意这里面存在的小陷阱
讲了这么多,还没讲到为什么需要使用虚函数构成多态呢,我们看到,在子函数中,我们可以改变属性值再重新还给基类,但是对于函数来说,只能重写,不能改写,所以我们没办法把从父类继承过来的函数修改一下再还回去的,这也是为什么必须使用虚函数才能构成多态,使用虚函数的时候,在虚函数表里,我们就可以重写同名函数,还能把虚函数表里父类的同名函数覆盖,因为虚函数表里,完全一样(函数名,形参,返回值一样,函数实现内容不一样)的函数只有一份,这样不就间接实现了函数改写的功能吗,我们改写完之后怎么传回去呢,既然虚函数表是利用虚指针访问的,那肯定传地址回去呀,把虚函数表的地址传回去不就行了吗
问题来了,既然是传地址,而且基类和派生类都有空指针,那空指针直接赋值可以吗
显然不可以,我们看以下代码
miniCar mc2;
int ** p=(int**)&mc2;
cout<<"子类 mc2 的虚函数表地址:"<<p[0]<<endl;
cout<<"子类 mc2 的虚函数表中虚函数的地址:0x"<<hex<<p[0][0]<<endl;
Car c2=mc2;
p=(int**)&c2;
cout<<"子类 c2 的虚函数表地址:"<<p[0]<<endl;
cout<<"子类 c2 的虚函数表中虚函数的地址:0x"<<hex<<p[0][0]<<endl;
Car &c3=mc2;
p=(int**)&c3;
cout<<"子类 c3 的虚函数表地址:"<<p[0]<<endl;
cout<<"子类 c3 的虚函数表中虚函数的地址:0x"<<hex<<p[0][0]<<endl;
可以明显看到,直接复制的话,c2拿不到虚函数表的地址,这是为什么呢???
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)