struct Animal{
int weight;
void run(){
cout << "animal run"<<endl;
}
};
struct Dog:Animal{
int age;
void run(){
cout<<"Dog run"<<endl;
}
};
int main(int argc, const char * argv[]) {
// insert code here...
Animal *p1 = new Dog();
p1->run();
Animal *p2 = new Animal();
p2->run();
Animal animal;
cout<<sizeof(animal)<<endl;
return 0;
}
打印结果
animal run
animal run
4
我们传入了指向dog对象的指针,预期的是调用子类dog里的run函数,可实际还是调用父类,要实现这点需要在父类函数添加virtual关键字
struct Animal{
int weight;
virtual void run(){
cout << "animal run"<<endl;
}
};
再运行,结果输出:
Dog run
animal run
16 // 架构不同这个数可能有差异
查看汇编代码,没加virtual时
0x100003192 <+66>: callq 0x1000031d0 ; Animal::run at main.cpp:12
0x1000031c3 <+115>: callq 0x1000031d0 ; Animal::run at main.cpp:12
可以看出两个指针都是调用同一地址,这个是父类函数地址;
加virtual时
0x100003091 <+81>: callq *(%rcx)
0x1000030ce <+142>: callq *(%rdx)
这时他们分别调用的两个寄存器上不同地址,很明显这就是virtual起的作用;
当不使用virtual时,对象地址默认是第一个成员变量地址,使用virtual后,其地址内存存储了其虚表的地址值,虚表里放着Animal里标记的虚函数的调用地址。
在C++里对象找方法都是直接去相应虚表里面找,这与OC子类父类层级找不同的。
网友评论