【问题标题】:C++ force implementation of method in child class but with a different signatureC++ 强制在子类中实现方法但具有不同的签名
【发布时间】:2018-08-23 16:33:28
【问题描述】:

有没有办法强制在子类中实现方法每个派生类的实现会有不同的签名?

我知道我可以做到这一点,使用纯虚拟:

class Base {
  public:
   virtual void getValue(string& s) = 0;
}

class Derived : public Base {
  public:
   void getValue(string& s);
}

上面,基类中的纯虚getValue强制派生类实现getValue。但我真正想做的是这样的:强制每个派生类实现 getValue() 但每个都有不同的签名:

class Base {
  public:
   void getValue() = 0;
}

class Derived_A : public Base {
  public:
   void getValue(string& s);
}

class Derived_B : public Base {
  public:
   void getValue(int *j);
}

上面的问题是,由于名称修改,每个签名实际上是一个不同的函数,因此 Derived_A 和 Derived_B 继承 getValue() = 0 并且编译器认为它们也是抽象的。

我一直在尝试一些不同的方法来做到这一点,但在我看来没有办法做到这一点。我在想我应该在基类中声明 getValue,然后确保每个派生类都实现它们的版本。

【问题讨论】:

  • 看看模板、mixin 和 CRTP,这些将打开一个超越动态多态性的可能性的整个世界。像void getValue() = 0; 这样的东西绝对是零意义顺便说一句。
  • @R Sahu- 感谢您纠正我的错字!
  • @πάντα ῥεῖ -- 谢谢。现在阅读 CRTP。看起来这可能正是我在这种情况下所需要的。
  • 回复:“我不应该在基类中声明 getValue”——也许吧。您在这里谈论的是编写代码;根本问题是设计问题之一。你想做什么?为什么在派生类中需要不同的签名,这些函数与基类中声明的函数有什么联系(如果有)?
  • @DanielGoldfarb 想象一下这可能你会如何使用这个功能,你想过吗?

标签: c++ abstract-class


【解决方案1】:

如果使用 CRTP 对您有用,您可以使用:

#include <string>

template <typename TypeSelector>
class Base {
  public:
     using type = typename TypeSelector::type;
     virtual void getValue(type t) = 0;
};

struct TypeSelector_A {
   using type = std::string&;
};

class Derived_A : public Base<TypeSelector_A> {
   public:
      void getValue(std::string& s) { /* Add real implementation */ }
};

struct TypeSelector_B {
   using type = int*;
};

class Derived_B : public Base<TypeSelector_B> {
   public:
      void getValue(int* j) { /* Add real implementation */ }
};

int main()
{
   Derived_A a;
   Derived_A b;
}

【讨论】:

  • 既然不能真正使用,为什么还要继承和虚函数呢?
  • @Slava,这质疑 CRTP 作为一个基本的、可行的概念。
  • 我不这么认为,我认为你的例子是滥用CRTP。
  • 为什么要使用中间选择器类?为什么不简单地使用template &lt;typename type&gt; class Base { public: virtual void getValue(type t) = 0; };
  • @Slava,如果Base 里面没有其他东西,那就是这样。如果Base 有使用getValue 的附加代码,那么它是对CRTP 的合法使用。
【解决方案2】:

但我真正想做的是这样的:强制每个派生类实现 getValue() 但每个都有不同的签名

拥有虚函数(抽象与否)的全部意义在于您可以将它与基类的指针或引用一起使用,这意味着您将使用基类中的函数签名。拥有你想要的东西是完全没用的。你想要的可以通过返回 std::variantstd::any 来实现,树中的每个虚函数都保持签名相同。

如果可能的话,您应该考虑如何使用这样的概念。如果你有这样的想法:

void foo( Base *b ) {
    if( auto *d = dynamic_cast<Derived_A *>( b ) ) {
       std::string str;
       d->getValue( str );
       ...
    }
    if( auto *d = dynamic_cast<Derived_B *>( b ) ) {
       int i = 0;
       d->getValue( &i );
       ...
    }
}

那么getValue()不需要是虚拟的,你只需要Base中的虚拟限制器。但这被认为是糟糕的设计。

【讨论】:

    猜你喜欢
    • 2019-07-09
    • 1970-01-01
    • 2015-10-27
    • 1970-01-01
    • 2013-02-28
    • 2014-03-28
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多