强制执行纯虚函数实现,可能使用不同的参数类型

时间:2019-07-15 05:34:46

标签: c++ c++11 inheritance polymorphism system-design

我目前有一个基类Env,它是一个接口,并且我有几个派生类。

class Env

{
    public:

        //method in question
        virtual std::tuple<Eigen::VectorXf,float,bool,std::string> step(const //what goes here?//)=0;

        virtual ~Env(); //virtual destructor
};

派生类示例如下(标题)

class MountainCar: public Env

{
    public:

        MountainCar();
        std::tuple<VectorXf,float,bool,std::string> step(const int) override;

};

现在,设计是所有环境都必须从Env继承。但是,我想强制所有环境来实现step()方法,这就是为什么基本Env中的step方法是纯虚拟的。

但是,每个派生的Env都可以在step方法中采用不同的参数类型,并且这应该是有效的替代(这些有效类型来自固定的已知集合)例如,mountain car用int参数定义了它。另一个环境CartPole使用VectorXf作为step参数。

最初,我使基类成为带有参数U的模板类,并将U传递给step方法。然后,派生类用于继承模板实例,例如从Env继承的MountainCar示例。但是,问题在于所有派生类都继承自基类的不同实例,并且我不能再将公共基指针用于多态。

如何设计具有C ++ 11功能的系统?

2 个答案:

答案 0 :(得分:5)

您的前提没有任何意义。让我们想象一下有可能:

class Base {
    virtual void step(/* something */);
};
class DerivedString : public Base {
    void step(std::string) override;
};
class DerivedInt : public Base {
    void step(int) override;
};

您打算怎么做?

std::unique_ptr<Base> bs = std::make_unique<DerivedString>();
bs->step(1);  // compiler error? runtime error?

std::unique_ptr<Base> bi = std::make_unique<DerivedInt>();
bi->step("one");  // compiler error? runtime error?

如果答案是“编译器错误”,则应删除虚函数和基类,因为它们没有提供任何值。

如果您的答案是“运行时错误”并且您使用的是C ++ 17,则可以使用std::any

class Base {
    virtual void step(std::any);
};
class DerivedString : public Base {
    void step(std::any v) override {
        step(std::any_cast<std::string>(v));
    }
    void step(std::string s);
};
class DerivedInt : public Base {
    void step(std::any v) override {
        step(std::any_cast<int>(v));
    }
    void step(int i);
};

这将导致std::bad_any_cast被抛出上方。


如果您没有C ++ 17,并且事先知道类型集,则可以预先声明函数的每个重载:

class Base {
    virtual void step(std::string) { throw runtime_error(); }
    virtual void step(int) { throw runtime_error(); }
};
// only subclass from this
template<typename T>
class BaseHelper : public Base {
    void step(T) override = 0; // replace with pure-virtual
}
class DerivedString : public BaseHelper<std::string> {
    void step(std::string s) override;  // compiler error when instantiated if forgotten
};
class DerivedInt : public BaseHelper<int> {
    void step(int i) override;
};

答案 1 :(得分:0)

如果要通过基类指针或引用调用它,则定义一个虚函数出于任何其他原因这样做是对语言的滥用。

自然,只有在完全知道签名的情况下,才能调用函数。如果不这样做,就不会有调用,也不会定义函数。

所以在您的情况下:

class Env {
    public:
       virtual 
         std::tuple<Eigen::VectorXf,float,bool,std::string> 
           step(const // What goes here?
                      // The thing YOU want to pass to this function in YOUR code,
                      // if you have an Env pointer or reference:
                      //     pEnv->step(42);
                      // If you don't have a reason to make such a call,
                      // just don't define the function.
               ) = 0;