我目前有一个基类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功能的系统?
答案 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;