【问题标题】:Overriding a pure virtual function from templated classes从模板类覆盖纯虚函数
【发布时间】:2014-03-08 02:47:51
【问题描述】:

我搜索了堆栈溢出,但没有找到可以准确回答我的问题的内容。我有一个只包含纯虚函数的接口类,我希望由派生自该类的类来实现这些纯虚函数。

我有一个接口,我将调用 BaseInterface,它定义了我希望在派生自该接口的所有类中覆盖的函数。在这个例子中,假设只有一个名为 toImplement 的纯虚函数。我创建了一个名为 Base 的类,它继承自 BaseInterface,并为继承的纯虚函数添加了一些功能。 Base 仍然是一个抽象类,因为它没有实现 BaseInterface 中的功能。

我有几个派生自 Base 的类,它们都受益于 Base 的通用功能,但指定了在运行 toImplement 时会发生什么他们的实例。这些类都应该是具体的并且满足 BaseInterface 设置的所有要求。下面我定义了一个名为Derived的类。

当 BaseInterface 和 Base 没有模板化时,所有这些都可以正常工作。代码编译并运行良好,无需在 Base 中定义 (1.) 或实现 (2.) toImplement。

但是我希望 toImplement 使用不同的类型。据我了解,在模板类中拥有纯虚函数是可以的。我在某些类型 T 上模板 BaseInterface 和 Base。当我没有在 Base 中定义 toImplement 时 (1. ),我无法编译,因为 Base 不知道在 tryUsingImplemented 中使用哪个 toImplement。如果我现在将定义添加到 Base,代码会预编译,但链接器找不到 Base::toImplement 的实现。最后,如果我在 Base(1. 和 2.)中定义和实现 toImplement,代码就会编译。

我不喜欢这个,因为我在 Base 中有一个 toImplement 的虚拟实现,我从不希望这个实现运行。此外,由于 Base 实现了 toImplement,因此不再需要 Derived 来实现它。这使得 BaseInterface 在我看来毫无用处。

谁能告诉我如何在 Derived 中强制实施 toImplement,而不必先在 Base 中实施有可能吗?

template <typename T>
class BaseInterface {
   virtual void toImplement(T & t) = 0;
};


template <typename T>
class Base : public BaseInterface<T> {
bool m_useImplemented;

public:
   explicit Base(bool useImplemented) : m_usedImplemented(useImplemented) {}

   void tryUsingImplemented(T & t) {
      if (m_useImplemented)
         toImplement(t);
   }  

protected:
   // 1: Defining toImplement pure virtual function in Base
   virtual void toImplement(T & t);
};

// 2. Implementing a version of toImplement in Base which does nothing
template <typename T>
inline void Base<T>::toImplement(T & t) {
   // do nothing
}

class Derived : public Base<int> {
public:
   explicit Derived(bool useImplemented) : Base<int>(useImplemented) {}

protected:
   // 3. implementing toImplement in Derived 
   void toImplement(T & t) {
      std::cout << "Doing stuff for Derived" << std::endl;
   }  

};

【问题讨论】:

  • 您可以提供纯虚函数的定义。如果您不希望派生类执行对Base::toImplement 的非虚拟调用,请将其设为私有函数。
  • 我试图尽可能简化我的问题,但我确实忘记将 BaseInterface::toImplement 定义为受保护的。它在原始代码中,所以问题不是访问权限之一

标签: c++ templates inheritance abstract-class pure-virtual


【解决方案1】:

如果您提供编译器错误消息以供将来参考,将会很有帮助。

但是,在这种情况下,我知道。您的代码中有两个错误:

  1. toImplement 在 BaseInterface 中是私有的。
  2. tryUsingImplemented 中的查找不会在基类中查找。您正面临lookup in dependent bases 问题。要修复它,请写this-&gt;toImplement(t)。

【讨论】:

  • 感谢您的回答。我相信问题确实是在依赖基础中查找。我删除了 Base 中纯虚拟的定义和实现,并将它们的调用替换为: this->toImplement 并且编译器现在知道使用 BaseInterface::toImplement
【解决方案2】:

如果您打算从派生类调用它,您需要在BaseInterface 中将toImplement 声明为protected。我已经从派生类中删除了所有覆盖方法,并将Derived::toImplement的参数类型替换为int,并且编译正常。后者是必须的,因为Derived不是模板,所以需要使用传递给Base的模板参数。

  #include <iostream>

  template <typename T>
  class BaseInterface {
  protected:
     virtual void toImplement(T & t) = 0;
  };


  template <typename T>
  class Base : public BaseInterface<T> {
  bool m_useImplemented;

  public:
     explicit Base(bool useImplemented) : m_useImplemented(useImplemented) {}

     void tryUsingImplemented(T & t) {
        if (m_useImplemented)
           toImplement(t);
     }  
  };

  class Derived : public Base<int> {
  public:
     explicit Derived(bool useImplemented) : Base<int>(useImplemented) {}

  protected:
     // 3. implementing toImplement in Derived 
     void toImplement(int & t) {
        std::cout << "Doing stuff for Derived" << std::endl;
     }  

  };

【讨论】:

  • 感谢您的回答!我忘记将 protected 关键字添加到 BaseInterface 但它在我的原始代码中,所以这不是问题。问题在于在 Base 中调用 toImplement,其中编译器不知道 toImplement 依赖于模板 T。通过使用 this->toImplement 可以解决此问题
  • 嗯,它用clang编译对我来说没有问题。但是,很高兴知道这个问题。
猜你喜欢
  • 2017-06-28
  • 2014-08-16
  • 2013-10-04
  • 2021-09-30
  • 2021-11-08
  • 2020-08-21
  • 1970-01-01
  • 2022-01-13
  • 2014-05-22
相关资源
最近更新 更多