C++ 通过类继承的多态实现原理以及虚函数表改写时机

class Parent{
public:
  virtual void func() { cout << "Parent" << endl; }
};

class Child : public Parent{
public:
  void func() { cout << "Child" << endl; }
};

int main()
{
  Child child;
  Parent *p4 = &child;

  p4->func();      //打印Child,父类指针p4竟然运行子类函数
  return 0;
}

关于C++多态,我刚开始学的时候有一个疑惑:在Parent *p4 = &child;的情况下:

p4明明是父类指针,怎么会调用到子类的成员函数呢?


请明确以下内容:

  • p4是指向父类的指针,没有实体,调用成员时,一切都会按照父类的偏移量使用。
  • 子类内存有父类那部分内容。
  • 编译器将重写的虚函数安排到一个特殊的地址(这个地址就是虚函数表,虚表指针就是指向这个地址)。
  • 编译器看到虚函数会覆盖虚函数表对应项。

根据以上基础内容,虚函数调用过程是:
1.按照父类偏移量偏移到虚表指针。
2.按照父类偏移量从虚表偏移到虚函数,这个虚函数就是被覆盖的虚函数。

那么为什么非虚函数不会调用到子类函数呢?

非虚成员是正常分配,是根据类自身偏移的。p4调用非虚成员,实际上就是调用从父类继承过来的那部分内存,所以调用的都是父类成员。

程序是编译后确定好的,子类(右值)各不相同(但是左右值地址相同、虚函数偏移量相同),看着像虚函数根据右值动态在变,所以被称为动态多态。
不要试图用指针一个个看对象的内存布局,C++标准没有规定布局,不同编译器对象内存布局不一定相同。


注意:如果子类的继承方式是private,由于父类的虚函数对子类不可见,子类不能override父类的虚函数,那么多态是无效的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C++中的多态性是通过虚函数实现的。在含有虚函数中,编译器会自动添加一个指向虚函数的指针,这个指针通常称为虚函数指针。虚函数是一个存储虚函数地址的数组,每个有一个对应的虚函数。当一个对象被创建时,会自动分配一个指向它的虚函数的指针。 虚函数指针的大小和虚函数的大小都与具体实现相关。在一般情况下,虚函数指针的大小为4或者8个字节,虚函数的大小取决于虚函数的个数。 以下是一个模拟实现: ```c++ #include <iostream> using namespace std; class A { public: virtual void func1() { cout << "A::func1" << endl; } virtual void func2() { cout << "A::func2" << endl; } }; class B : public A { public: virtual void func1() { cout << "B::func1" << endl; } }; int main() { A* a = new A(); B* b = new B(); cout << "size of A: " << sizeof(A) << endl; cout << "size of B: " << sizeof(B) << endl; cout << "size of a: " << sizeof(a) << endl; cout << "size of b: " << sizeof(b) << endl; a->func1(); a->func2(); b->func1(); b->func2(); delete a; delete b; return 0; } ``` 输出结果: ``` size of A: 8 size of B: 8 size of a: 8 size of b: 8 A::func1 A::func2 B::func1 A::func2 ``` 在上面的代码中,我们定义了两个A和B,其中B继承自A。A和B都含有虚函数,因此编译器会为它们添加虚函数指针。在main函数中,我们创建了一个A对象和一个B对象,并输出了它们的大小以及指针的大小。接着我们调用了每个对象的虚函数,可以看到B对象的func1()覆盖了A对象的func1(),而A对象的func2()没有被覆盖。最后我们删除了这两个对象,避免内存泄漏。 需要注意的是,虚函数指针的大小和虚函数的大小是不确定的,取决于具体实现。此外,虚函数指针通常被放在对象的开头,因此虚函数通常被放在内存中较靠前的位置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朴人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值