【问题标题】:An elegant way to pass derived type to base member template function?将派生类型传递给基本成员模板函数的优雅方法?
【发布时间】:2012-11-27 22:04:49
【问题描述】:

我有一个名为“ValueChecker”的类

具有以下成员函数:

template<typename T>
bool ValueChecker::checkMe( std::ostringstream &oss, T &me) { 
   std::cout << "Default checkMe() for " << typeid(me).name() << std::endl; 
   return true;
}

ValueChecker 类旨在对派生类的值进行一些简单的检查。 checkMe() 最终将专门用于不同的派生类:

class Airplane : public ValueChecker {
   friend class ValueChecker;
   [...]
}


template<>
bool ValueChecker::checkMe<Airplane>( std::ostringstream &oss, Airplane &me) { 
   ...    
   /* Actually, this code is generated from a simple file which translates
    * a simple language into C++ code.  So that a non-developer can write
    * the simple checks.
    *
    * ValueChecker itself has utility functions that may be called in the
    * template specialization which are shared across all types.
    */

}

这可行,但是当您查看调用时,checkMe 的声明存在一个小问题:

int main() {
  Airplane plane;
  std::ostringstream oss;

  if( plane.checkMe( oss, plane)) {
    cout << "Values are bogus!  " << oss.str() << endl;

  return 0;
}

我调用 plane.checkMe(oss,plane)。但是,我也可以通过另一架飞机而不检查飞机。此外,调用是多余的?这意味着,理论上,编译器应该知道根据平面的类型调用哪个模板函数。也不需要将其作为参数传递吗?无论如何,最好不要消除最后一个论点。所以像这样的电话会很好:

if( plane.checkMe(oss)) { ... }  // Calls the right template specialization.

我就是无法让它工作。 C++ 大师能帮我吗?谢谢。

【问题讨论】:

  • 我们不能在 typeid 中传递这个指针吗?
  • 一开始这似乎是相当奇怪的设计。为什么Airplane 派生自ValueChecker?为什么checkMe() 接受T 类型的参数时(从您的问题判断)它应该只检查this

标签: c++ templates derived-class base-class


【解决方案1】:

对于您给定的代码,您实际上不需要使用templatefriend。而是使用继承,并将checkMe() 方法设为protectedvirtual 方法。然后重写派生类中的checkMe() 方法。如果您不需要默认实现,也可以将其设为纯虚拟。这是基于您的示例的快速代码 sn-p 。 (注意this指针的使用。)

class ValueChecker {
protected:
    virtual bool checkMe() { 
        std::cout << "Default checkMe() for " << typeid(this).name() << std::endl; 
        return true;
    }
};

class Airplane : public ValueChecker {
public:    
    virtual bool checkMe() {
        std::cout << "Airplane checkMe() for " << typeid(this).name() << std::endl;
        return true;
    }
};

int main() {
  Airplane plane;
  plane.checkMe();
}

除了特定于派生类本身的逻辑之外,如果您想在一个或多个派生类中使用一些“通用”逻辑,则您需要一个默认实现。在这种情况下,请使用范围解析运算符来访问基类的逻辑。

    bool Airplane::checkMe() {
        std::cout << "Airplane checkMe() for " << typeid(this).name() << std::endl;

        // use the "common" logic from the base class (if required)
        ValueChecker::checkMe();

        return true;
    }

【讨论】:

  • @Bitdiot 如果您的问题已得到解决,您能否为答案投票并接受答案? (我更喜欢我的:))
【解决方案2】:

您可能希望将其实现为纯虚拟方法。

class ValueChecker
{
public:
    virtual bool checkMe(std::ostringstream& oss) = 0;
};

class Airplane : public ValueChecker
{
public:
    virtual bool checkMe(std::ostringstream& oss);
};

这样你就可以调用plane.checkMe(oss),然后飞机的checkMe-Method就会被调用。

【讨论】:

    【解决方案3】:

    有一个常用的技巧:http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern 这可以为您解决问题。

    【讨论】:

    • CRTP 在这里并不是真正需要的。有一个更简单的解决方案,虽然我同意它在问题中的实现方式,但它看起来确实像 CRTP 的解决方案。
    猜你喜欢
    • 2015-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-25
    相关资源
    最近更新 更多