需要知道一些常识,一个类所有的函数都是再code代码区中唯一的存放一份。而数据成员则是每个对象存储一份,并按照声明顺序依次存放。
类A中有了虚函数就会再类的数据成员的最前面添加一个vfptr指针(void vfptr),这个指针用来指向一个vtable表(一个函数指针数组)(一个类只有一个该表),该表存储着当前类的所有 虚函数 的地址。这样vfptr就成为了一个类似成员变量的存在。访问虚函数的时候通过vfptr间址找到vtable表,再间址进而找到要调用的函数。这样就在一定程度上摆脱了类型制约。
只要vptr的值不同,那么访问函数成员的时候使用的vtable表就不同,就可能访问到不同类的函数成员。B类对象中的vptr指向B类自己的vtable。
当B类继承A类的时候,因为A中有虚函数,编译器就自动的给B类添加vfprt指针和vtable表。也可以理解为B类继承来了A类中的那个vptr指针成员。
当A类指针指向B类对象时,发生假切割。要知道这个过程只是切掉A类中没有的那些成员,由于vptr是从A类中继承来的,所以这个量仍将保留。而对于vptr的值则不会改变,仍然指向B类的vtable表。所以访问F1函数的时候是通过B类的vtable表去寻址的,自然就是使用子类的函数。
当B类的指针指向A类的对象时(当B类存在新增数据成员时可能出错),同理。
而对于普通函数则受类型的制约,(因为没有vptr指针)使用哪个类的指针调用函数,那么所调用的就是那个累的函数。
总而言之,普通函数通过对象或指针的类型来找所调用的函数,而虚函数是通过一个指针来找到所要调用的函数的。
你是只调用子类自己的函数吗?
#include<iostream>
using namespace std;
class B0
{
public:
virtual void display()
{
cout<<"B0"<<endl;
}
};
class B1:public B0
{
public:
void display()
{
cout<<"B1"<<endl;
}
void displayB1()
{
cout<<" My is B1"<<endl;
}
};
class D1:public B1
{
public:
void display()
{
cout<<"D1"<<endl;
}
};
void fun(B0 ptr)
{
ptr->display();
}
void funB1(B1 ptr)
{
ptr->displayB1();
}
int main()
{
B0 b0,p;
B1 b1;
D1 d1;
p=&b0;
fun(p);
p=&b1;
fun(p);
funB1((B1 )p); //调用子类函数
p=&d1;
fun(p);
return 0;
}
基类不知道派生类虚函数的存在的。
用平常的虚函数表逻辑说的话,就是基类指针的上下文里是没有虚函数表存在的。你硬塞一个虚函数表只会导致数据错乱。派生类的指针给基类指针赋值的时候指向位置会变的。这个时候基类指针会指向派生类对象内的一个没有虚函数表的子对象。
C++中派生类对基类成员的访问形式主要有以下两种:
1、内部访问:由派生类中新增成员对基类继承来的成员的访问。
2、对象访问:在派生类外部,通过派生类的对象对从基类继承来的成员的访问。
三种继承方式下,派生类对基类成员的访问规则。
1、私有继承的访问规则
2、公有继承的访问规则
3、保护继承的访问规则
答案是B
首先子类对象的构造必然会先构造基类的对象,所以基类的构造函数和子类的构造函数都会调用,所以count++了两次,所以先输出2
然后show是虚函数,通过基类指针调用会调用子类的方法,所以调用的是D中的show方法,所以输出的是y,也就是120。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)