虚拟静态功能功能的解决方法

时间:2019-01-21 00:21:18

标签: c++ inheritance static virtual

让我说一堂课

class StateVector {
protected:
    float* _v;

public:

    StateVector():_v(new float[size()]) {}
    virtual ~StateVector() { delete [] _v; }

    virtual size_t size() = 0;

    // ...

};

class PositionState : public StateVector {
public:
    size_t size() { return 3; }
    float* x()    { return _v; }
};

class MovingState : public PositionState {
public:
    size_t size() { return PositionState::size() + 3; }
    float* v()    { return _v + PositionState::size(); }
};

此处的目的是允许派生类通过覆盖size()来指定状态向量的大小。 (此信息必须对拥有基础数组的基类StateVector的构造函数可用)。

但是,由于以下几个原因,这并不理想:

  • 首先,在此实现中,size()对于类的所有实例必须/将是相同的。但是在这种情况下,没有什么可以阻止同一类的不同实例对size()持有不同的看法。

  • 第二,其他类需要生成一个实例以查询适当的大小:

    template <typename State>
    class StateTransition {
    
        Matrix<float> _m;
    
        // constructor for Matrix takes #rows, #cols
        StateTransition():_m(State().size(), State().size()) {}
    
        // ...
    
    };
    

这很愚蠢,因为对于所有State,size()都是相同的。在这种情况下,size()可能会很大,并且在StateTransition的构造函数中(通过构造两个State)将分配该大小的两个数组,然后立即将它们扔掉!

最后,期望每个派生类都将携带其基状态的超集,因此基类的size()永远不应比派生类小–但是由于我们无法遍历继承树,因此我不还不知道以编程方式强制执行此操作的方法。这是次要的问题,但是如果有一种干净的方法来解决,那就太好了。

能够写作最有意义:

class StateVector {
    float* _v;
    StateVector:_v(new float[size()]) {}

    virtual static size_t size() = 0;
};

class PositionState {
    static size_t size() { return 3; }
    // ...
};

// etc.

template <typename State>
class StateTransition {

    Matrix<float> _m;

    StateTransition():_m(State::size(), State::size()) {}
};

但是,这里(以及其他地方)的其他答案表明不允许使用虚拟静态函数(其中一些无助地表明它“没有意义”或“将无用”)。

什么是惯用的方法来解决此问题,从而使派生类尽可能容易地遵循规则?

1 个答案:

答案 0 :(得分:0)

虽然我不确定为什么您坚持使用虚函数而不是传递给基类的构造函数的数字参数,但是有一种解决方案涉及虚函数,但涉及另一类:

class StateVectorInfo {
public:
  virtual int size() const = 0;
protected:
  ~StateVectorInfo () = default;
};

class PositionStateInfo : public StateVectorInfo {
  PositionStateInfo (); // don't create other instances
public:
  virtual int size() const;
  static PositionStateInfo info; // single instance
};

PositionStateInfo PositionStateInfo::info; // a definition is needed

class StateVector {
    float* _v;
public:
    StateVector (const StateVectorInfo& info):
       _v(new float[info.size()]) {
    }
};