C++ ';不可访问的直接基地';由多重继承引起的

C++ ';不可访问的直接基地';由多重继承引起的,c++,multiple-inheritance,C++,Multiple Inheritance,剧透警报:也许是个愚蠢的问题。:) 现在,我明白了这段代码是不可能工作的。我想知道为什么基本是中间私有的,因此通过中间派生的不应该看到它。那么,这种模糊性是从何而来的呢?在构造函数中?这与重写函数无关。这与转换有关。它实际上也与可访问性(即“私有”之类)没有直接关系。这里有一个更简单的例子 struct A { int a; }; struct B : A { }; struct C : B, A { }; // direct A can't be referred to! 通过先转换为B,然

剧透警报:也许是个愚蠢的问题。:)


现在,我明白了这段代码是不可能工作的。我想知道为什么<代码>基本是
中间
私有的,因此通过
中间
派生的不应该看到它。那么,这种模糊性是从何而来的呢?在构造函数中?

这与重写函数无关。这与转换有关。它实际上也与可访问性(即“私有”之类)没有直接关系。这里有一个更简单的例子

struct A { int a; };
struct B : A { };
struct C : B, A { }; // direct A can't be referred to!
通过先转换为
B
,然后再转换为
A
,可以引用间接
A
对象:

B *b = &somec;
A *a = b;
不能对直接对象执行此操作。如果您试图直接转换为
A
,则有两种可能。因此,对于给定的
派生的
对象,不可能引用直接
对象的非静态数据成员

请注意,可访问性与可见性是正交的。有些东西即使不可见也可以访问(例如通过限定名称引用),有些东西即使不可访问也可以可见。即使将上述所有派生声明为私有
,问题仍然会出现:访问是最后检查的-它不会影响名称查找或转换规则


此外,任何人都可以使用定义的行为(C++标准对此例外)使用一个C样式的CAST来转换成一个明确的私有基类,即使通常不会允许这样做。还有一些朋友和班级本身可以自由转换

约翰的回答涵盖了基本事实。但还有一点。所以,考虑一下

struct Base
{
    Base( int ) {}
    void foo() const {}
};

struct Intermediate: Base
{
    Intermediate( int x )
        : Base( x )
    {}
};

struct Derived: Intermediate, Base
{
    Derived( int x )
        : Intermediate( x )
        , Base( x )         // OK
    {}
};

int main()
{
    Derived o( 667 );
    o.foo();                // !Oops, ambiguous.
    o.Base::foo();          // !Oops, still ambiguous.
}
当我编译时,我得到了,正如现在(在Johannes的回答之后)你所期望的

C:\test> gnuc x.cpp x.cpp:15: warning: direct base 'Base' inaccessible in 'Derived' due to ambiguity x.cpp: In function 'int main()': x.cpp:25: error: request for member 'foo' is ambiguous x.cpp:4: error: candidates are: void Base::foo() const x.cpp:4: error: void Base::foo() const x.cpp:26: error: 'Base' is an ambiguous base of 'Derived' C:\test> msvc x.cpp x.cpp x.cpp(15) : warning C4584: 'Derived' : base-class 'Base' is already a base-class of 'Intermediate' x.cpp(2) : see declaration of 'Base' x.cpp(7) : see declaration of 'Intermediate' x.cpp(25) : error C2385: ambiguous access of 'foo' could be the 'foo' in base 'Base' or could be the 'foo' in base 'Base' x.cpp(25) : error C3861: 'foo': identifier not found C:\test> _ 在第一种情况下,例如,
Base
是一个接口,并且只需要一个子对象,您可以使用虚拟继承

<>虚拟继承通常会增加一些运行时开销,Visual C++不太喜欢它。 但它允许您“继承”接口的实现,如Java和C#:

微妙之处:我更改了继承列表顺序,以避免g++愚蠢地警告初始化顺序

烦恼:Visual C++通过显性来发布关于继承(实现)的警告。这就像“警告:您正在使用标准的主函数”。哦,好吧,把它关掉


干杯,

这不是一个编译器错误。我想调用派生->你的方法(5)应该可以。。。毕竟,在基础和中间阶段,Yormethod都是虚拟的,所以为什么不能定义自己的实现呢。您没有以任何方式调用基函数,因此公私tihng应该无关紧要?有趣的是,在VS2010中,我得到了这个编译器警告。。。警告C4584:“派生”:基类“base”已经是“Intermediate”的基类@Kyle C:是的,我的错。我认为这是一个错误。我发现为什么会出现这种情况的一个常见原因是,使用纯虚拟基类的行为类似于接口。其次,通过在第三代/第四代派生类中重新说明“Base”的继承,您可以强调派生类必须遵循特定的模式,以获得代码的清晰性。我建议在接口类型类的继承中添加“virtual”。通过限定名引用某个对象如何成为即使不可见也可以访问的对象的示例?@nakiya
class a{int a;void f(){int a;/*outer a is not visible*/}A::A
来引用它。在
f
中的本地
a
之后,类成员是可访问的(因为它是同一个类),但其名称被本地
a
隐藏。您的类比是否支持继承树?如果我私下从
A
继承
B
,公开从
B
继承
C
,那么
A
应该对
C
不可见(受保护将使之成为可能)。因此,如果我也从
A
继承
C
C
理想情况下应该只看到它的
A
而不是
B
s
A
。但是,我同意这不是事实。“Nakiya技术上讲,这可能是有意义的(我认为在java中,私有成员名称不是继承的,与C++相反),但是C++规则不是这样的:无障碍对于任何东西都不重要——它只在所有其他东西建立之后才被检查。我不知道这样做的理由-可能是出于简单的原因(朋友的姓名查找可能与非朋友的姓名查找完全不同)。我的问题是,当您通过类型为
Intermediate
的句柄使用它时,而不是单独使用派生名称(在我的问题中)应该没有解决问题,因为
Intermediate
是从
Base
@nakiya私下派生出来的:假设“句柄”是指“引用”,那么我在你的问题中看不到这一点,但那不是问题。尽管如此,编译器可能仍然会对
派生的
定义发出警告。但是为什么您要直接从
派生的
中的
基继承?干杯,我说的“手柄”是指“参考或指针”。将此问题(和我的答案)作为第二个问题的答案:
struct Base
{
    Base( int ) {}
    void foo() const {}
};

struct Intermediate: Base
{
    Intermediate( int x )
        : Base( x )
    {}
};

struct Derived: Intermediate, Base
{
    Derived( int x )
        : Intermediate( x )
        , Base( x )         // OK
    {}
};

int main()
{
    Derived o( 667 );
    o.foo();                // !Oops, ambiguous.
    o.Base::foo();          // !Oops, still ambiguous.
}
C:\test> gnuc x.cpp x.cpp:15: warning: direct base 'Base' inaccessible in 'Derived' due to ambiguity x.cpp: In function 'int main()': x.cpp:25: error: request for member 'foo' is ambiguous x.cpp:4: error: candidates are: void Base::foo() const x.cpp:4: error: void Base::foo() const x.cpp:26: error: 'Base' is an ambiguous base of 'Derived' C:\test> msvc x.cpp x.cpp x.cpp(15) : warning C4584: 'Derived' : base-class 'Base' is already a base-class of 'Intermediate' x.cpp(2) : see declaration of 'Base' x.cpp(7) : see declaration of 'Intermediate' x.cpp(25) : error C2385: ambiguous access of 'foo' could be the 'foo' in base 'Base' or could be the 'foo' in base 'Base' x.cpp(25) : error C3861: 'foo': identifier not found C:\test> _
struct Base
{
    Base( int ) {}
    void foo() const {}
};

struct Intermediate: Base
{
    Intermediate( int x )
        : Base( x )
    {}
};

struct ResolvableBase: Base
{
    ResolvableBase( int x ): Base( x ) {}
};

struct Derived: Intermediate, ResolvableBase
{
    Derived( int x )
        : Intermediate( x )
        , ResolvableBase( x )
    {}
};

int main()
{
    Derived o( 667 );
    o.ResolvableBase::foo();    // OK.
}
struct Base
{
    Base( int ) {}
    virtual void foo() const = 0;
};

struct Intermediate: virtual Base
{
    Intermediate( int x )
        : Base( x )
    {}
    void foo() const {}     // An implementation of Base::foo
};

struct Derived: virtual Base, Intermediate
{
    Derived( int x )
        : Base( x )
        , Intermediate( x )
    {}
};

int main()
{
    Derived o( 667 );
    o.foo();    // OK.
}