【问题标题】:‘base’ is an inaccessible base of ‘deriv’‘base’是‘deriv’的一个不可访问的基础
【发布时间】:2012-12-07 17:03:41
【问题描述】:

为什么derivderiv 中无法访问base?程序使用class deriv : public base编译。

#include <cstdio>

class base
{
};

class deriv : base
{
  public:
  void f(deriv, int){printf("deriv::f(deriv, int)\n");}
  void f(base){printf("deriv::f(base)\n");}
};

int main()
{
  deriv d;
  d.f(d);
}

17: error: ‘base’ is an inaccessible base of ‘deriv’
17: error:   initializing argument 1 of ‘void deriv::f(base)’

因为已经有两个人搞错了,我就加粗问:base为什么要公开继承?它只能从deriv 内部访问。

【问题讨论】:

    标签: c++ inheritance


    【解决方案1】:

    如果您使用class 关键字定义类,则成员和基类默认为私有。

    如果基类需要公开,则要么显式声明它public(正如你在问题中提到的那样),要么使用默认公开的struct关键字。

    为什么 base 需要公开?

    在这种情况下,您对f(base) 的调用需要将deriv 转换为base,并且只有在基类可访问的情况下才能进行这种转换。由于是私有的,因此在需要转换的main 中无法访问。

    【讨论】:

    • 为什么需要公开?
    • @DoruGeorgescu:我已经更新了答案:仅当基类可访问时才允许转换为基类。
    • @MikeSeymour:“由于是私有的,因此无法在 main 中访问”。我认为转换在任何地方都是不可能的,即使在任何一个类的成员函数中也是如此。
    • @DoruGeorgescu 否则您无法访问基类(就像您尝试做的那样)
    • @Nawaz:你为什么这么认为?成员和朋友可以访问私有成员和基类;这就是“私人”的意思。因此,deriv 的成员肯定可以进行转换,如 here 所示。
    【解决方案2】:

    因为是私有继承的:

    class deriv : base
    

    class 的默认继承是私有的,这意味着其他类和函数无权访问派生类的基类。


    您的示例中有一个小问题。这个:

      deriv d;
      d.f(d);
    

    由于切片,它不会做你期望它做的事情。

    如果我们通过将f 的签名更改为这样来解决上述问题:

    void f(base&){printf("deriv::f(base)\n");}
    

    访问deriv的基类还是有问题,因为它是从基类私有继承的。

    【讨论】:

    • @DoruGeorgescu 在您的具体示例中,main 无法将deriv 转换为base。可能需要更好的措辞:)
    【解决方案3】:

    您似乎错误地假设调用deriv::f(base) 时从derivbase 的转换发生在“deriv 内部”,因此必须是可访问的。不是这种情况。调用函数时,初始化函数参数所需的所有转换都发生在调用者的上下文中。它们不在“derive 内部”。它们发生在“外部世界”。在您的情况下,“外部世界”无法访问deriv-to-base 转换。

    在您的特定情况下,main 正在尝试将 deriv 转换为 base。而main 无法做到这一点,因为它无法访问deriv 的私​​有基础。只是为了进行实验,您可以将 int main() 声明为 deriv 的朋友,代码将编译。

    【讨论】:

    • 感谢您的回答。我是否有权怀疑这是编译器对隐私的相当粗略的保护?我知道私有类继承破坏了Liskov substitution principle。这使得结果有点违反直觉。
    • main 可以访问base,但不能通过deriv 访问basederiv 确实可以访问 base。很好,我用private继承是我的错... :-)
    • 试图理解这种行为,我想象编译器对待私有继承的类就像对待私有成员一样。这对我来说并不令人满意,我终于明白编译器采用了一种简单的机会主义方法:它将访问说明符视为“网关”。在 main 中,不能通过派生类的转换访问私有继承的基类。我相信,这也适用于指向这些类的指针和指向这些类的指针。
    • @Doru Georgescu:您对指针(和引用)是正确的,但“指向指针的指针”不属于这里。 “指针指向指针”是一个完全不同的故事。 deriv ** 不能转换为 base **,即使 basepublic 基类。此外,基类确实类似于数据成员。基础和数据成员都是完整对象的子对象。基的访问语法与数据成员的访问语法不同,但在许多其他方面它们非常相似。
    • 确实,基类类似于数据成员,“网关”规则也适用于它们。但是,关于deriv **的问题,我希望你是在开玩笑吧?请告诉我发生了什么,一个链接或至少一个关键字......
    猜你喜欢
    • 1970-01-01
    • 2012-03-28
    • 2017-01-12
    • 1970-01-01
    • 1970-01-01
    • 2022-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多