C++多态之虚函数本质

2021-11-13  本文已影响0人  wangwhatlh
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子类父类层级找不同的。

上一篇 下一篇

猜你喜欢

热点阅读