重新指定继承的虚方法如何使其正确消除歧义?

时间:2016-04-28 17:47:35

标签: c++ c++11

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

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

我设法通过以下方式重现了这个问题:

simple.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

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

问题是我评论过的内容;一旦我将这些东西添加到文件中,编译器和我的测试都很高兴。因此直观地说这是有道理的,因为现在有为虚拟方法定义的具体方法,并且编译器以前不会/不能猜测我想要的超类方法。

我的问题有两个:

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

2 个答案:

答案 0 :(得分:2)

您具有菱形继承,因此在继承InterfaceA时需要指定虚拟关键字。请参阅代码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()。因此,调用IS绑定到this的对象。

答案 1 :(得分:0)

您的ImplB课程中有2 InterfaceA个继承树。您需要使用虚拟继承(参见https://isocpp.org/wiki/faq/multiple-inheritance)。