提出这个问题,因为我觉得以后在派生类中需要我的基础的成员变量。是否有保护它们的缺点?
编辑:编辑以更好地表明我的意图。
编辑:@sbi:这也错了吗?此类将用于在其他类中进行错误记录和检索。从它衍生或使用它的对象是否更好 - 我不知道。但我认为getter和setter方法就是这个类的全部内容。
class ErrorLogger
{
public:
//Making this function virtual is optional
virtual void SetError(const char*, ...);
const char* GetError() const;
protected:
char* z_ErrorBuf;
};
答案 0 :(得分:21)
封装是OO的主要特征之一。将数据封装在类中意味着类的用户不能破坏类的数据的不变量,因为类的状态只能通过其成员函数来操作。
如果允许派生类访问其基类的数据,则 派生类需要注意不要使基类'数据的不变量 无效。这会将封装抛出窗口,这是错误的。 (所以getters and setters,BTW。)
多年来,我发现自己越来越少地使用protected
,即使对于成员函数也是如此。如果一个类完全实现了一个简单的概念,那么它的所有状态都应该可以通过它的公共接口来操作。如果派生类需要“后门”潜入,那么我通常会质疑我的设计。 (这并不是说我从不使用protected
。我发现我越来越少需要它。)
答案 1 :(得分:2)
我很好奇其他人会回答的问题。
除了访问器范例之外,您可以将它们声明为私有并使用受保护的Getter和Setter方法。如果您的基类实现发生了变化,那么您只需要修改那些getter和setter。
答案 2 :(得分:2)
如果您认为子类需要稍后访问这些变量,那么请将它们保护起来。
只要满足上述条件,就没有缺点。
如果您想采取额外步骤并保护您的变量不受外部访问,您可以始终创建私有成员变量,然后使用受保护的方法来访问/修改这些私有变量。
答案 3 :(得分:2)
继承只是使用类的另一种方式。它更加耦合,通过使您的成员变量受到保护,您可以结合更多,因此您不应该在不知道对每个继承类的影响的情况下更改它们。如果它是你的基类和你继承的类,那么可能不会有任何伤害,但是你无法控制如何访问成员(锁定,记录,读/写,持久性......)。 p>
答案 4 :(得分:2)
在个人情况下,我通常会尝试将protected
的使用限制为virtual
件。
我认为protected
的任何其他用途在概念上等同于public
。从某种意义上说,如果您编写非虚拟保护方法,请将其写为公共方法。字段相同。如果该字段在公开时会破坏某些内容,如果它受到保护,它也会破坏某些内容。
这并不意味着拥有受保护的字段或非虚拟方法很糟糕,它只是意味着您必须小心谨慎地使用它们,并且知道某个人可以在某处使用这些东西并且可能只需通过推导就可以打破你的课程。
答案 5 :(得分:1)
受保护的数据具有公共数据的所有缺点,因此您也可以公开它们。
答案 6 :(得分:1)
如果您将它们设为私有,并且稍后决定它们需要可以被派生类访问,则可以将它们更改为受保护而不会影响依赖于该类的任何代码。您还可以选择添加受保护的访问者。
如果你让它们受到保护并且后来决定它们应该是私有的,那么更改它们可能会破坏依赖它们的现有代码。
我个人的经验法则是将所有内容设为私有,并在必要时将其提升为可见性链。
答案 7 :(得分:1)
只要您没有故意设计要继承的类,就没有可靠的方法来猜测哪些方法应该是虚拟的,哪些成员应该受到保护。你唯一能确定的是,你很可能猜错了。
不要乱用它,使用sealed关键字并将成员设为私有。你总是可以在以后重构,无论如何你都必须这样做。
答案 8 :(得分:1)
制作“公开”的东西会创建一个约束所有继承类的契约。制作“受保护”的东西会与直接 - 继承的类创建契约,但不会强迫这些类将这样的契约提供给任何后代。
如果有人希望任何继承它的人可以使用基类的源代码,并且期望基类永远不会改变(通常这意味着使用基类的原因是允许公共类)基类的成员和属性可以与派生类互换使用,而不是减少派生类所需的代码量,如果所有公共方法都是虚拟的或直接与虚方法绑定,那么使用它并没有太大的缺点受保护的字段而不是受保护的虚拟getter / setter。如果后代类需要更改字段的使用方式,它可以简单地覆盖使用它们的所有方法。
如果人们期望派生类可以在层次结构中上面的类不完全已知或不可变的情况下创建,那么拥有受保护的getter / setter可能更合适,但是可以保留这个责任与谁在层次结构中创建“不透明”层。
示例:集合可能会维护一个名为“count”的字段。集合的基本版本可以以易于维护始终保持项目数量的字段的方式存储事物,但派生版本可能以难以管理的方式存储事物。通过一个名为“count”的字段,基类承诺它的直接后代将保持该字段中的项目数。派生类可能以不同方式存储事物,因此“计数”字段没有意义。这样的类可以用只读属性遮蔽count字段;它的后代会知道他们必须阅读一个属性,而原始类的后代会知道他们可以阅读一个字段。
最重要的一点是,类中受保护的东西只与直接后代建立契约,这些后代可以决定是否为子后代提供类似的契约。
附录:通过添加受保护的虚拟getter和setter获得的唯一功能是派生类可以更改基类代码访问字段/属性的方式。有时候这是必要的,但更多时候会产生问题。例如,如果集合可能经常删除最近添加的项目,则派生类可以包装事物,以便添加的最后几个项目保存在小的“奖励”集合中,并在添加足够的附加项目之后传送到主集合。主集合的代码将期望其自己的“计数”字段指示主集合中有多少项。如果后代类重写“count”属性以包含其自己的项,则主代码将中断。后代类应该 shadow 计数字段,以便其后代将看到包含奖励项目的计数,但基类仍然会看到仅包含其自己项目的计数。
答案 9 :(得分:0)
您的整体课程设计将告诉您是否最终会受到受保护的成员。无论你是私人的,受保护的还是公共的,这都不是在石头上凿刻的东西,所以你可以随意创建你的课树,而不必过多思考。如果一开始你不知道派生类是否会使用该成员,并且以何种方式,你肯定会在编码时找到它。
最重要的是决定什么是公共vs /私人,因为这是你向外界介绍你的课程的方式。
答案 10 :(得分:0)
您不会出于某种原因公开会员。即使这些成员可以自由设定或获得。您提供虚拟公共制定者和吸气剂。完全相同的原因,你不应该保护成员。相反,您应该提供受保护的setter和getter。对称性非常强。
答案 11 :(得分:-1)
提供受保护的getter并且可能设置为私有内部变量,它是更多的代码,但它更清晰。