【问题标题】:Override number of parameters of pure virtual functions覆盖纯虚函数的参数个数
【发布时间】:2011-02-24 13:31:26
【问题描述】:

我已经实现了如下接口:

template <typename T>
class Variable
{
public:
  Variable (T v) : m_value (v) {}
  virtual void Callback () = 0;
private:
  T m_value;
};

一个合适的派生类会这样定义:

class Derived : public Variable<int>
{
public:
  Derived (int v) : Variable<int> (v) {}
  void Callback () {}
};

但是,我想派生Callback 接受不同参数的类(例如:void Callback (int a, int b)). 有什么办法吗?

【问题讨论】:

  • 你怎么称呼Callback(在基类中)?
  • 不确定“在基类中调用 Callback”是什么意思。实际上,我不能拥有Variable 实例,因为Callback 是纯虚拟的。我误解了你的评论吗?
  • 重申 KennyTM 问题:如何从指向 Variable 的引用/指针调用 Callback?一个不同的问题(或者可能再次重新表述相同的问题)是如何将参数传递给最派生的对象?
  • 您希望派生类对同一个变量或不同的变量有不同的回调吗?
  • @dribeas:回答你的第二个问题,参数是按值传递的。 @MadKeithV:两者都不是。我想在每个派生类中都有一个名为 Callback 的方法,该方法具有 void 返回类型并接受不同的参数(相对于基类)。因此,例如我们可以有void DerivedA::Callback (int)void DerivedB::Callback (char)。换句话说:我想强制执行该方法的返回类型及其名称。

标签: c++ interface virtual overloading


【解决方案1】:

这是我多次遇到的问题。

这是不可能的,并且有充分的理由,但有一些方法可以实现基本相同的目标。就个人而言,我现在使用:

struct Base
{
  virtual void execute() = 0;
  virtual ~Base {}
};

class Derived: public Base
{
public:
  Derived(int a, int b): mA(a), mB(b), mR(0) {}

  int getResult() const { return mR; }

  virtual void execute() { mR = mA + mB; }

private:
  int mA, mB, mR;
};

在行动:

int main(int argc, char* argv[])
{
  std::unique_ptr<Base> derived(new Derived(1,2));
  derived->execute();
  return 0;
} // main

【讨论】:

  • 确实有启发性的解决方案。只是出于我的好奇,为什么你认为我想要实现的目标“有充分的理由”是不可能的?
  • 因为语言不是这样设计的。您对虚拟方法唯一的余地是返回类型的协方差。您可以(可以想象)要求一个“参数”接口类,然后使用该类的派生版本并在方法中继续 dynamic_cast ......但是,那闻起来:p
【解决方案2】:

即使这样的事情是可能的,将其作为虚函数也不再有意义,因为无法通过指向基类的指针多态地调用派生实例。

【讨论】:

    【解决方案3】:

    不要认为这是可能的,因为你永远无法将它接口回变量。 这就是我的意思

    int a=0; int b = 0;
    Variable<int>* derived = new Derived();
    derived->Callback(a, b); //this won't compile because Variable<int> does not have Callback with 2 vars.
    

    【讨论】:

    • 这就是重点!你写的就是我想要达到的。我也想过使用函数指针。尽管如此,指针函数必须匹配函数签名(args+return 类型),所以我们回到第一个问题。
    • 如果你想从一个引用/指针调用Callback(a,b),那么它必须是基本接口的一部分。
    【解决方案4】:

    我知道这是一个公认的答案,但是有一种(丑陋的)方法可以实现你想要的,尽管我不推荐它:

    template <typename T> 
    class Variable 
    { 
    public: 
      Variable (T v) : m_value (v) {}
      virtual void Callback (const char *values, ...) = 0; 
    
    private: 
      T m_value; 
    };
    
    class Derived : public Variable<int> 
    { 
    public: 
      Derived (int v) : Variable<int> (v) {} 
      virtual void Callback (const char *values, ...) {
      } 
    };  
    

    现在,您可以使用:

      int a=0; 
      double b = 0; 
      Variable<int>* derived = new Derived(3); 
      derived->Callback("");
      derived->Callback("df", a, b);
    

    您需要 values 参数来获取方法内的剩余参数。您还需要知道参数类型,并像 printf 一样传递它们。

    此方法容易出错,因为您必须将 values 上的参数类型与实际参数类型相匹配。

    【讨论】:

    • 还有有趣的解决方案!感谢您指出。我同意它更容易出错,但也更灵活。
    • 从技术上讲,您不需要参数字符串,只要每个派生类只提供一个“重载”即可。您确实需要一些设置参数,但如果您事先知道将传递多少个参数,则可以忽略它。
    【解决方案5】:

    您必须在接受这些参数的基类中添加回调的重载。也有可能做坏事,比如接受一个 void*,或者传入一个原始的指向字节的指针。 更改虚函数签名有效的唯一情况是当您将返回值覆盖为与原始返回值具有多态性的东西时,例如*这个。

    【讨论】:

      猜你喜欢
      • 2013-10-04
      • 2021-09-30
      • 2020-08-21
      • 2014-05-22
      • 2022-01-13
      • 2013-01-16
      • 2016-04-19
      • 1970-01-01
      • 2021-11-01
      相关资源
      最近更新 更多