c++ - 重新指定继承的虚拟方法如何使其能够正确消除歧义?

标签 c++ c++11

我正在使用 googlemock 做一些有趣的事情,并决定将我的类分成纯虚拟类和具体实现,以避免需要为我的模拟使用特殊的外壳。然而,编译器开始提示:

error: undefined reference to 'vtable for <ConcreteClass>'

我成功地通过以下方式重现了该问题:

简单.h:

namespace simple {

class InterfaceA {
 public:
  virtual ~InterfaceA() {}

  virtual int MethodOne() const = 0;
};

class InterfaceB : public InterfaceA {
 public:
  ~InterfaceB() override {}

  virtual int MethodTwo() const = 0;
};

class ImplA : public InterfaceA {
 public:
  ImplA(int to_return);
  ~ImplA() override {}

  int MethodOne() const override;

 private:
  int to_return_;
};

class ImplB : public InterfaceB, public ImplA {
 public:
  ImplB();
  ~ImplB() override {}

  // int MethodOne() const override;
  int MethodTwo() const override;
};
}  // namespace simple

简单.cc

#include "simple.h"

namespace simple {

ImplA::ImplA(int to_return) : to_return_(to_return) {}
int ImplA::MethodOne() const { return to_return_; }

ImplB::ImplB() : ImplA(5) {}
// int ImplB::MethodOne() const { return ImplA::MethodOne(); }
int ImplB::MethodTwo() const { return 2; }
}  // namespace simple

问题是我注释掉的部分;一旦我将这些东西添加到文件中,编译器和我的测试都很满意。因此直观上这是有道理的,因为现在为虚拟方法定义了具体方法,而编译器以前不会/无法猜测我想要哪些父类(super class)方法。

我的问题有两个:

  1. ImplA::MethodOne() 的规范如何允许调用它,因为它不是静态变量?
  2. 在创建时,ImplB 对象中的某处是否存在隐式 ImplA 指针,允许它调用 ImplA 上的方法,尽管该指针并未被调用静态方法?

最佳答案

您有菱形继承,因此从 InterfaceA 继承时需要指定 virtual 关键字。查看代码here

#include <iostream>
using namespace std;

namespace simple {

class InterfaceA {
 public:
  virtual ~InterfaceA() {}

  virtual int MethodOne() const = 0;
};

class InterfaceB : virtual public InterfaceA {  // <-- note the virtual keyword
 public:
  ~InterfaceB() override {}

  virtual int MethodTwo() const = 0;
};

class ImplA : virtual public InterfaceA { // <-- note the virtual keyword
 public:
  ImplA(int to_return);
  ~ImplA() override {}

  int MethodOne() const override;

 private:
  int to_return_;
};

class ImplB : public InterfaceB, public ImplA {
 public:
  ImplB();
  ~ImplB() override {}

  //int MethodOne() const override;
  int MethodTwo() const override;
};

ImplA::ImplA(int to_return) : to_return_(to_return) {}
int ImplA::MethodOne() const { return to_return_; }

ImplB::ImplB() : ImplA(5) {}
// int ImplB::MethodOne() const { return ImplA::MethodOne(); }
int ImplB::MethodTwo() const { return 2; }
}  // namespace simple


int main() {
    simple::ImplA implA(100);
    cout << implA.MethodOne() << endl << endl;

    simple::ImplB implB;
    cout << implB.MethodOne() << endl;
    cout << implB.MethodTwo() << endl;


    return 0;
}

顺便说一句,您在问题中写了一个静态方法...那里没有静态方法,当您调用 ImplA::MethodOne() 时,您实际上调用了 this->ImplA::MethodOne()。因此,调用与 this 对象相关联。

关于c++ - 重新指定继承的虚拟方法如何使其能够正确消除歧义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36921974/

相关文章:

c++ - 函数中的参数数量未知

c++ - "lib"头的库文件名在codeblocks和vs9编译器中无法识别

C++/多态性/虚函数/为什么我的子类的函数没有被调用?

c++ - volatile 和 virtual 成员如何影响 C++ 合成移动构造函数?

C++ 内存释放

c++ - boost::filesystem、std::getenv 和并发

c++ - std::unique_ptr 使用带有少量参数的自定义删除器

c++ - 类与枚举类作为索引类型

c++ - 将引用转发为仿函数参数的优点

c++ - 为什么这个 `int` 有错误的值?