我的看法是,在OOP中,公共接口的作用是确保对象始终处于有效状态(这是不能将memcpy
转换为非Pod类型的重要原因之一)。例如。一个非常基本的,学究的示例:(请忽略类似于Java的set / get):
class Restricted {
protected:
int a;
public:
Restricted() : a{0} {}
// always returns a non-negative number
auto get() const -> int {
return a;
}
auto set(int pa) -> void {
if (pa < 0)
a = 0;
else
a = pa;
}
auto do_something() {
// here I code with the assumption that
// a is not negative
}
};
在此示例中,类
Restricted
的建模方式是Restricted
对象始终持有非负数。这就是我为Restricted
定义有效状态的方式。通过查看接口,我可以说Restricted ::get
将始终返回非负数。用户无法获取Restricted
来保留负数。使
a
受保护,以使该选项可以轻松扩展该类。因此,让我们用允许所有数字的类型扩展Restricted
:class Extended : public Restricted {
public:
Extended() { a = -1; }
auto set(int pa) -> void {
a = pa;
}
auto do_something() {
// now a can be negative, so I take that into account
}
};
乍一看一切都很好。
Extended
不会修改Restricted
或它的行为。 Restricted
仍然相同,我们只添加了另一个允许负数的类型。除了我们对
Restricted
的最初假设不再成立。用户可以轻松获得一个包含负数的Restricted
对象(处于无效状态的对象),因为:C++
允许切片对象而没有任何警告:Restricted r = Extended{};
// or
Extended e;
e.set(-24);
Restricted r = e;
// and then:
r.do_something(); // oups
没加起来的东西:
将
Extended
创建为Restricted
的子类是错误的吗?如果是这样,为什么?如果我希望
a
始终为非负数,将protected
设置为a
是错误的吗?为什么? protected
不允许更改我班级的行为。C++
允许对象切片是错误的吗?以上全部
其他的东西
最佳答案
如果我期望a始终为非负数,则将a设置为保护是错误的吗?为什么?
是的,这是错误的。 Restricted
的界面要求a
为非负数。这就是类型设置的不变性。而且它没有virtual
函数,以允许派生类覆盖该不变式。
通过违反该不变性(并且由于您好奇地缺少virtual
函数),Extended
打破了OOP的基本规则:派生类实例应能够被视为(公共)基类的实例。那并不意味着切片;我的意思是,您应该能够将Extended
传递给采用指向/ cc的指针/引用的函数,并且一切都应该像在与Restricted
对话一样工作。
将Extended创建为Restricted的子类是错误的吗?如果是这样,为什么?
这样做是错误的:
用Extended
a
代替protected
。
将private
的界面设置为非Restricted
。
C ++允许对象切片是错误的吗?
没有。