假设一个类代表一个3x3矩阵,并在其构造函数中取9个任意数字,并让该类具有inverse()方法。由于NOT并非所有矩阵都是可逆的,因此inverse()方法返回一个可选值(或可空指针),调用者必须在运行时检查它。
然而,某些3x3矩阵总是可逆的,只要矩阵中的值遵循某些规则,例如: 3D旋转矩阵。我们可以用子类来编纂它,它不允许直接构造,但是通过使用一些特殊规则来构造,例如围绕笛卡尔轴的旋转角度。
最终结果是这个层次结构,它应该允许层次结构的客户端在使用子类时具有编译时安全性(例如,客户端保证object.rotate(rotationMatrix.inverse())将始终有效,假设rotationMatrix属于RotationMatrix类型:
class Matrix {
public:
Matrix(double e_0_0, double e_0_1, double e_0_2,
double e_1_0, double e_1_1, double e_1_2,
double e_2_0, double e_2_1, double e_2_2) {
...
}
std::unique_ptr<Matrix3x3> inverse() const {
if (isInvertible) {
return std::unique_ptr(new Matrix3x3(...));
}
return std::unique_ptr();
}
}
class RotationMatrix : public Matrix3x3 {
public:
static RotationMatrix getRotationAroundX(double angle) {
return asRotationMatrix(Matrix(1, 0, 0,
0, cos(angle), -sin(angle),
0, sin(angle), cos(angle)));
}
RotationMatrix inverse() const {
return asRotationMatrix(*Matrix::inverse().get()));
}
private:
static const RotationMatrix3D& asRotationMatrix(const Matrix3x3& matrix) {
return static_cast<const RotationMatrix3D&>(matrix);
}
}
所以要打破原来的问题:
答案 0 :(得分:3)
在这里,您点击了circle/ellipse problem:
最好不得不使用不同的类并使用组合:
class RotationMatrix {
public:
static RotationMatrix getRotationAroundX(double angle) {
return { Matrix(1, 0, 0,
0, cos(angle), -sin(angle),
0, sin(angle), cos(angle))};
}
RotationMatrix inverse() const {
return {*Matrix::inverse().get()});
}
const Matrix3x3& AsMatrix() const { return matrix; }
private:
static RotationMatrix(const Matrix3x3& matrix) : matrix(matrix) {}
Matrix3x3 matrix;
};
答案 1 :(得分:0)
这些约束应该通过接口强制执行,在这种情况下,通过构造函数和任何可能的可用mutator(setter)。这就是你描述的模式。
为了防止未来的开发人员通过继承搞乱您的类的内部,通过声明private
来使相关数据成员(即您想要保护的成员)无法访问。
从C ++ 11开始,你也可以声明你的类final
,这样任何人都无法继承它。
答案 2 :(得分:0)
在C ++中是否有一种方法可以防止(或者至少清楚地向未来的开发人员发出信号)子类必须不引入新的状态?不幸的是答案是否定的。任何OO语言中的所有层次结构都将其用作通用规则:子类可以完成其父类所做的所有操作,并可以添加其他方法和属性
如果您有特殊要求,您可以做得更好,就是撰写文档并在那里明确说明。