20

这是我的代码 -

#include<iostream>
using namespace std;

class base
{
public:
    void sid()
    {
    }  
};

class derived : private base
{
public:
    void sid()
    {
    }
};

int main()
{
    base * ptr;
    ptr = new derived; // error: 'base' is an inaccessible base of 'derived'
    ptr->sid();
    return 0;
}

这会产生编译时错误。

error: 'base' is an inaccessible base of 'derived'

既然编译器会尝试调用基类sid(),为什么会出现这个错误?有人可以解释一下吗。

4

7 回答 7

35

我怀疑问题是您不能将派生指针转换为基指针,因为继承是私有的。

于 2010-09-09T08:25:29.493 回答
16

$11.2/4 个州-

N 的基类 B 可在 R 处访问,如果

  • B 的一个发明的公共成员将是 N 的公共成员,或
  • R 出现在 N 类的成员或朋友中,而 B 的发明公共成员将是 N 的私有或受保护成员,或
  • R 出现在派生自 N 的类 P 的成员或朋友中,而 B 的发明公共成员将是 P 的私有或受保护成员,或
  • 存在一个类 S,使得 B 是在 R 处可访问的 S 的基类,而 S 是在 R 处可访问的 N 的基类。”

这里'B'是'Base','N'是'Derived','R'是main。

  1. 考虑第二个项目符号-'R 出现在 N 类的成员或朋友中,......'。本条款不适用于“R”(主)既不是“N”(派生)的成员也不是朋友

  2. 考虑第三个项目符号-'R 出现在 P 类的成员或朋友中......'。由于与上述相同的原因,该条款也不适用

  3. 考虑第 4 个项目符号 - 此条款再次不适用

因此,我们可以得出结论,“Base”不是“Derived”的可访问类。

$11.2/5 个州 -

如果基类是可访问的,则可以将指向派生类的指针隐式转换为指向该基类的指针(4.10、4.11)。[注意:因此类 X 的成员和朋友可以将 X* 隐式转换为指向 X 的私有或受保护的直接基类的指针。-结束注释]

由于在 中访问时Base不是可访问类,因此从派生类到基类的标准转换格式不正确。因此错误。Derivedmain

编辑2:

研究一些流行编译器的错误消息,这应该可以帮助您更好地理解。请注意“无法访问”一词如何在所有错误消息中如此频繁且一致地弹出

参考来自标准草案 N3000。我还没有下载最新的草稿:)

GCC prog.cpp:在函数'int main()'中:prog.cpp:27:错误:'base'是'derived'的不可访问的基础</p>

Comeau Online“ComeauTest.c”,第 26 行:错误:不允许转换为无法访问的基类“base” ptr = new derived;

VS2010 错误 C2243: 'type cast' : 从 'derived *' 到 'base *' 的转换存在,但无法访问

于 2010-09-09T08:28:40.100 回答
8

Chusbad 提供了涉及标准的深入解释,我将尝试提供一个易于理解的解释。

在 C++ 中,有 3 个访问级别说明符publicprotectedprivate. 这些旨在确定 WHO 可以访问方法、属性或基类。它在面向对象的语言中很典型。

在这里,您选择private了继承。从概念上讲,这意味着您试图隐藏Derived从外部继承的事实Base,这通常意味着这是一个实现细节。

结果,“外部”没有意识到这种关系。这是由编译器通过此inaccessible消息强制执行的。

从设计的角度来看,private通常不需要继承。要么适用 Liskov 替换原则并且您使用public继承,要么它是一个实现细节并且您使用组合。

于 2010-09-09T09:29:46.757 回答
6

你知道它class derived继承自class base,但main()函数不知道它。该main()函数不知道它的原因是您class derivedclass base.

因此,当您尝试分配new derivedtoptr时,指针类型不兼容。

于 2010-09-09T08:27:00.567 回答
5

试试这个:

#include<iostream>
#include<conio.h>
using namespace std;

class base
{
      private:
      public:
          virtual void sid() // You might want to declare sid virtual
             {
                  cout<<"base";
             } 
          virtual ~base() // You then probably need a virtual destructor as well.
             {
             } 
};

class derived : public base //public inheritance
{
      private:
      public:
             void sid()
             {
                  cout<<"derived";
             }
};

int main()
{
    base * ptr;
    ptr = new derived;
    ptr->sid();
    getch();
    return 0;
}
于 2010-09-09T08:26:25.927 回答
1

这给出了错误 C2243: 'type cast' : 从 'derived *' 到 'base *' 的转换存在,但不可访问此派生类已被私有继承。因此当派生 get 创建发生时,不会创建基类对象。创建派生对象首先调用去创建没有发生的基类对象。解决方案是公开派生类。无论您是否使用带有成员函数的 virtual 关键字都没有关系。

于 2010-09-09T09:44:34.283 回答
0

您需要将基类中的 sid() 函数声明为虚拟函数。虚函数可以用派生类代替。否则,您可能会收到编译器错误。

于 2010-09-09T08:26:16.800 回答