使用受保护的成员有什么不好的选择?

时间:2019-05-27 23:33:40

标签: c++ c++11 cpp-core-guidelines

最近有人告诉我,受保护的成员是坏人,经过阅读后,看来确实是共识(例如http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rh-protected)。那我该怎么办呢?

假设我正在处理一组Widget类,并且每个小部件都应该具有许多公共属性(例如foo,bar和baz)。我可以如下定义基类:

class Widget
{
public:
    virtual ~Widget() = default()

    Foo foo() const;
    Bar bar() const;
    Baz baz() const;

    virtual void someInterfaceMethod() = 0;

protected:
    Foo m_foo;
    Bar m_bar;
    Baz m_baz;
};

Widget::foo() { return m_foo; } // etc.

在这种特殊情况下,什么是实现它的更好方法?

我应该使Widget成为仅接口类,然后在每个派生的Widget中定义那些成员吗?我应该将它们设为私有,并在派生类的构造函数中使用get()和set()方法吗?我应该将它们设为私有并更改Widget构造函数以将其作为参数吗?如果直到构造后才能完全初始化它们,该怎么办?

1 个答案:

答案 0 :(得分:0)

“ X是好的”和“ X是坏的”可能太黑白了,无法描述事物。一如既往,没有绝对的好坏,只有达到目标的相对水平。

关于某些人为什么不喜欢将受保护的成员变量直接暴露给子类代码的原因,可能是出于与他们不喜欢将公共成员变量暴露给其他代码相同的原因-因为这样做可以使之成为现实。将来很难更改您的实现,而又不会破坏依赖于当前实现细节的其他代码。

通过强制子类代码进行方法调用而不是直接访问成员变量,您可以强制该代码通过您可以控制的途径,因此将来可以进行修改而无需修改调用码。例如,某天您可能决定每次修改m_baz时都想打印一条日志消息(或其他内容)。如果所有10,000个呼叫站点都在您的班级上调用set_m_baz(newVal),则这是在一个文件中执行的一行更改。如果OTOH,您允许他们所有人直接进行m_baz = newVal;,那么您现在必须修改所有10,000个呼叫站点才能获得所需的结果,根据您的情况,拥有者的前景可能从乏味到不可能调用代码等。