我看到它的方式,在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++
允许对象切片是错误的吗?答案 0 :(得分:6)
如果我希望a总是非负的,那么设置为受保护是不对的?为什么呢?
是的,这是错的。 Restricted
的界面要求 a
为非负面。这是该类型设置的不变量。并且它没有virtual
函数来允许派生类覆盖该不变量。
通过违反该不变量(以及由于您好奇缺少virtual
函数),Extended
打破了OOP的基本规则:派生类实例应该能够被视为一个实例一个(公共)基类。这并不意味着切片;我的意思是,你应该能够将一个Extended
传递给一个带有Restricted
指针/引用的函数,并且一切都应该像是在与Extended
交谈一样。< / p>
将Extended创建为Restricted的子类是不对的?如果是这样,为什么?
错误地说:
制作a
protected
代替private
。
将Restricted
的界面设为非virtual
。
C ++允许对象切片是不对的?
没有
答案 1 :(得分:1)
C ++为你提供了一把枪,可以同时射击你的两只脚。情况一直如此。
如果要防止所描述的情况发生,请删除基类的复制构造函数,并让派生类的复制构造函数负责复制基类。
您也可以使用私有继承。
您可以选择最佳解决方案来满足您的班级设计要求。