【问题标题】:Why calling a protected static method in derived classes is allowed?为什么允许在派生类中调用受保护的静态方法?
【发布时间】:2013-05-30 14:10:08
【问题描述】:

不允许在派生类中调用受保护的构造函数,如 here 所述。

接受的答案解释说,protected 仅在 A 类的对象是 B 类的子对象时才授予对基类 A 对象成员的访问权限。到目前为止,一切顺利。

但是,为什么允许(至少在 GCC 4.6.3 中)调用静态保护方法?具体来说,以下编译对我来说没有任何意义,而注释行则没有:

class A 
{
protected:
    A() {}
    static A makeA() { return A(); }
};

class B: public A
{
public:
    static A makeAFromB()
    {
        return makeA(); // compiles
        // return A();  // does not compile
    }
};

从哲学上讲,构造函数非常类似于返回类 A 的对象的静态方法,这就是为什么我在这里没有得到行为差异的原因。

【问题讨论】:

  • 您应该将return A::A() 更改为return A()。它仍然无法编译,但这次将是与protected 访问相关的原因,使问题更加清晰。
  • 你说得对,已编辑。

标签: c++ inheritance


【解决方案1】:

您说得对,protected 仅授予对嵌入式基础对象的访问权限的方式可能令人惊讶……但这是有充分理由的。假设您有几个派生自Base 的类,其中一个类中的一个方法想通过一些引用或指针对任意Base 对象执行操作......它可能是Base 它正在摆弄是另一个派生链的一部分,考虑到它对受保护成员函数的使用,它对Base 对象有其他行为期望。您正在有效地删除另一个派生类的预期封装,防止它强制执行预期的不变量,走出良好 OO 行为的世界......将这种洞察力应用于您的特定场景,C++ 规则阻止您使用受保护的构造函数当实际上没有派生对象可以嵌入Base 对象时,创建一个预期具有由某个派生类管理的不变量的子对象。

另外,protected 用于构造函数的方式具有明显的效用——它阻止类的构造(使用该构造函数),除非是作为派生类的子对象,或者从基类的成员函数(例如 @987654327 @ 在您的示例中)-它们是静态成员函数还是非静态成员函数都无关紧要...所有成员函数始终对类充满。

忽略 private/protected/public 对于静态成员函数的直观含义有什么用处?您是说您希望它们实际上是私有的,如果这是您想要的行为,那么只需将它们设为私有/如果您需要它们可访问,请将它们保护起来。显然,根据我第一段中的理由,受保护的访问受到限制。

【讨论】:

  • 感谢您的回答 :) 事实上,我所期望的是可以从 Derived 调用 Base 的受保护构造函数。当我意识到这不可能时,我尝试使用我希望工作的受保护的makeA,但由于我之前的期望变成了错误,我不再确定(而且这个简单的黑客提供了完全相同的功能)。但是您对我的问题的标题是正确的:显然受保护的静态方法应该可以在派生类中调用,否则与私有静态方法没有区别。
  • @Boris:“预计 Base 的受保护构造函数可以从 Derived 调用” - 是的,也曾预料到这一点! :-) - 希望上面的推理有助于解释“为什么不”方面。与makeA 的关键区别在于,实现仍在A 的控制之下……它可以决定A 封装的边界,而让派生类使用构造函数放弃控制。干杯。
  • 上面的推理确实有帮助,以及您的附加评论 :) 我仍然很生气我不能调用析构函数,但是至少有一个很好的理由;- )
【解决方案2】:

静态方法是继承的,因为它们在子类的方法中可用。我们可以使用子类的名称调用静态方法,或者使用子类的实例,或者在子类的主体中没有限定。

【讨论】:

    【解决方案3】:

    但是,为什么允许(至少在 GCC 4.6.3 中)调用静态保护方法?

    因为这就是标准所说的。适用于protected 成员的可访问性的约束(并且您链接的答案很好地解释了)在 C++11 标准的第 11.4/1 段中定义,其第一句指定:

    当非静态数据时,应用超出第 11 条中所述的附加访问检查 成员或非静态成员函数是其命名类 (11.2) 的受保护成员。 [...]

    附加访问检查不适用于静态成员或静态成员函数。

    【讨论】:

    • 好的,感谢您的澄清! (以及标准中指定“非静态”的引用)
    猜你喜欢
    • 1970-01-01
    • 2016-09-13
    • 2020-04-01
    • 1970-01-01
    • 2011-11-07
    • 2013-10-01
    • 1970-01-01
    • 2013-11-12
    • 1970-01-01
    相关资源
    最近更新 更多