【发布时间】:2019-06-14 09:13:22
【问题描述】:
假设我有一堂课:
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()) {} // ... };
这很愚蠢,因为对于所有States,size() 将是相同的。在这种情况下,size() 可能会非常大,并且在StateTransition 的构造函数中(通过构造两个States)分配两个该大小的数组,然后立即将它们丢弃!
最后,预计每个派生类都将携带其基类状态的超集,因此基类的 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()) {}
};
但是,此处(和其他地方)的其他答案表明不允许使用虚拟静态函数(其中一些无益地暗示它“没有意义”或“没有用”)。
解决这个问题的惯用方法是什么,使派生类尽可能容易地遵循规则?
【问题讨论】:
-
为什么不能在构造函数中传递
size作为参数? -
@KunalPuri
StateTransition如何访问该信息? -
virtual在这里帮不上忙。在基类的构造函数中调用size()将调用基类的版本。 -
@trbabb 为什么不能通过定义数据成员将该信息存储在基类中?并在需要时归还?
-
@KunalPuri 因为,根据问题,这需要构造一个实例来查询大小,这是不必要/任意昂贵的。
标签: c++ inheritance static virtual