【问题标题】:Inheriting pure virtual methods with different arguments in different derived classes在不同的派生类中继承具有不同参数的纯虚方法
【发布时间】:2019-05-14 04:19:44
【问题描述】:

我已经在基类中声明了一个纯虚方法,但我想让不同派生类中的参数集有所不同。

我当前的代码是重载基类中的函数,如下所示:

class Base {
protected:
    virtual void function(arg_set_first) = 0;
    virtual void function(arg_set_second) = 0;
}

class Derived_First: public Base {
private:
    void function(arg_set_first);
    void function(arg_set_second) { } // do nothing
}

class Derived_Second: public Base {
private:
    void function(arg_set_first) { } // do nothing
    void function(arg_set_second);
}

它可以工作,但我认为它很难看,因为每个派生类中都有冗余实现。我想删除它们。

如何将基类中的纯虚函数更改为具有可变参数集,这些参数将在实现时指定?有办法吗?

【问题讨论】:

  • "我在基类中声明了一个纯虚方法" 不,你没有。您已经声明了 两个 纯虚方法。函数不仅仅是 C++ 中的名称。
  • 在基类中,不要将它们声明为纯虚拟。为他们提供无所事事的实现。
  • @Eljay 谢谢,我刚刚在 Base 类中将它们更改为具有空主体的虚函数。它可以正常工作,但我不确定这是一个“好”的设计..
  • 构成“好设计”的东西是罐头虫。我在这方面有强烈的意见,但我认为我的意见不符合 SO 的格式。 ;-)
  • 这个“有效”是什么意思?给定 Base 指针/引用的客户会乐意让其中一种或另一种方法不执行任何操作,具体取决于它是哪种派生类型?

标签: c++ inheritance design-patterns


【解决方案1】:

严格来说,你不能在 C++ 中这样做——方法的参数列表(以及这些参数的类型)被认为是方法的类型签名的一部分,因此子类的虚方法只能覆盖/实现父类的虚方法,前提是它们具有相同的名称和相同的确切参数。

也就是说,您可以通过使用数据结构而不是直接传递参数来伪造它。例如:

class Base {
protected:
    virtual void function(const std::map<std::string, std::variant> & args) = 0;
}

通过上面的方法,您有一个可以采用任何一组命名参数的方法,以一组键值对的形式。然后由子类(及其调用者)就使用哪些参数名称和参数值达成一致。这种方法的缺点是效率较低且更难使用(调用者每次要调用该方法时都必须创建和填充std::map,并且该方法必须检查std:map 的内容和图弄清楚如何处理它们);但是,如果您主要关心的是灵活性而不是性能(例如,因为不会经常调用该方法),那么这种方法可以很好地工作。

另一种方法是使用多重继承,并为这两个方法中的每一个指定单独的接口,并且(只是为了方便)还为想要实现两者的子类指定一个接口类:

class BaseFirst {
protected:
    virtual void function(arg_set_first) = 0;
}

class BaseSecond {
protected:
    virtual void function(arg_set_second) = 0;
}

class BaseBoth : public BaseFirst, public BaseSecond {
};

class Derived_First: public BaseFirst {
private:
    virtual void function(arg_set_first) {...}
};

class Derived_Second: public BaseSecond {
private:
    virtual void function(arg_set_second) {...}
};

class Derived_Both: public BaseBoth {
private:
    virtual void function(arg_set_first) {...}
    virtual void function(arg_set_second) {...}
};

由于任何特定的调用代码都知道它将要调用哪些function 方法(以及不会调用),它可以简单地在其API 中指定适当的指针/引用类型(例如BaseFirst * , BaseSecond *, or BaseBoth *) 来反映它的要求,编译器会为你保证只有真正满足这些要求的对象才能传递给它。

【讨论】:

    猜你喜欢
    • 2011-01-07
    • 1970-01-01
    • 1970-01-01
    • 2016-03-04
    • 1970-01-01
    • 2023-02-09
    • 1970-01-01
    • 2021-02-07
    • 2021-11-02
    相关资源
    最近更新 更多