首页 > 解决方案 > 子类型的对象在c ++中使用哪个vtable

问题描述

当我想执行这行代码时,它不会编译

    baseArray[1]->function5(); 

但是在 Derived 3 的 vtable 中,function5 应该指向 Derived1 中的 function5。所以我认为它应该输出 Derived1::function5()。但似乎在 Base 类中找到了 function5()

我只是想知道 Derived3 继承自 Derived1,为什么它仍然检查被调用的函数是否存在于 Base 类中?

请参考以下代码。谢谢您的帮助!

#include <iostream>
using namespace std;

class Base {
public:
  virtual void function1();
  virtual void function2();
  virtual void function3() = 0;
  void function4();
};

class Derived1 : public Base {
public:
  void function1();
  virtual void function5();
  void function6();
};

class Derived2 : public Base {
public:
  void function2();
  void function3();
  void function4();
  void function5();
};

class Derived3 : public Derived1 {
public:
  void function3();
};

void Base::function1(){
  cout << "Base::function1()" << endl;
}

void Base::function2(){
  cout << "Base::function2()" << endl;
}

void Base::function4(){
  cout << "Base::function4()" << endl;
}

void Derived1::function1(){
  cout << "Derived1::function1()" << endl;
}

void Derived1::function5(){
  cout << "Derived1::function5()" << endl;
}

void Derived1::function6(){
  cout << "Derived1::function6()" << endl;
}

void Derived2::function2(){
  cout << "Derived2::function2()" << endl;
}

void Derived2::function3(){
  cout << "Derived2::function3()" << endl;
}

void Derived2::function4(){
  cout << "Derived2::function4()" << endl;
}

void Derived2::function5(){
  cout << "Derived2::function5()" << endl;
}

void Derived3::function3(){
  cout << "Derived3::function3()" << endl;
}

int main(){
  Base *baseArray[] = { new Derived2, new Derived3 };
  baseArray[1]->function5(); //why the code doesn't compile when I call function5() here? 
                             //in vtable of Derived 3, function5 should points to function5 in Derived1
                             //so I think it should output Derived1::function5()

  dynamic_cast<Derived3*>(baseArray[1])->function5();
  
  baseArray[1]->function6(); //same question, why it doesn't call function6 in Derived1?
                             //which vtable does baseArray[1] use?

  dynamic_cast<Derived3*>(baseArray[1])->function6();
}

标签: c++polymorphismvirtualvtable

解决方案


C++ 是一种静态类型语言。这意味着必须在编译时知道对类型、成员、变量等的引用。

baseArray[1]->function5();andbaseArray[1]->function6();不编译的原因是因为baseArray[1]被声明为 a Base*but function5()and function6()are not 的成员Base。就那么简单。这与 vtables 无关。这只是编译器如何选择在运行时实现虚拟方法调用的分派的实现细节,但这不是 C++ 标准所要求的。

编译器不知道Base*指针实际上指向一个Derived3对象。这个事实直到运行时才确定。这是多态性的一个关键特征。

要正确调用function5()function6()您需要将Base*指针类型转换为具有您要访问的成员的派生类型,正如您已经发现的那样。请注意,如果转换失败,dynamic_cast指针将返回nullptr,您没有检查,例如:

// Derived1 and Derived2 are not related, but each has its own function5()...
if (Derived1 *d1 = dynamic_cast<Derived1*>(baseArray[index]))
    d1->function5();
else if (Derived2 *d2 = dynamic_cast<Derived2*>(baseArray[index]))
    d2->function5();

另一方面,如果您预先知道准确和正确的类型(如您的示例中所示),则可以static_cast改用,例如:

static_cast<Derived1*>(baseArray[index])->function5();

推荐阅读