nak*_*iya 19 c++ multiple-inheritance
剧透警报:也许是一个愚蠢的问题.:)
#include <iostream>
using namespace std;
class Base
{
public:
virtual void YourMethod(int) const = 0;
};
class Intermediate : private Base
{
public:
virtual void YourMethod(int i) const
{
cout << "Calling from Intermediate" << i << "\n";
}
};
class Derived : private Intermediate, public Base
{
public:
void YourMethod(int i) const
{
cout << "Calling from Derived : " << i << "\n";
}
};
int main()
{
}
Run Code Online (Sandbox Code Playgroud)
有人可以向我解释为什么会抛出编译器警告:
main.cpp:21: warning: direct base ‘Base’ inaccessible in ‘Derived’ due to ambiguity
Run Code Online (Sandbox Code Playgroud)
现在,我知道这段代码无法运行.我想知道为什么.Base是私有的Intermediate所以它不应该是可见的Derived通过Intermediate.那么模糊性来自何处?在构造函数中?
Joh*_*itb 28
这与重写函数无关.它与转换有关.它实际上与可访问性(即"私有"或类似)无直接关系.这是一个更简单的例子
struct A { int a; };
struct B : A { };
struct C : B, A { }; // direct A can't be referred to!
Run Code Online (Sandbox Code Playgroud)
您可以A通过先转换为B然后转到A以下来引用间接对象:
B *b = &somec;
A *a = b;
Run Code Online (Sandbox Code Playgroud)
您无法使用直接A对象执行此操作.如果您尝试直接转换为A,它将有两种可能性.因此,不可能在A给定Derived对象的情况下引用直接对象的非静态数据成员.
请注意,可访问性与可见性正交.即使它不可见,也可以访问某些东西(例如通过合格的名称引用它),即使它不可访问,也可以看到某些东西.即使将声明所有上述派生private,问题仍将显示:最后检查访问 - 它不会影响名称查找或转换规则.
此外,任何人都可以使用C风格的强制类型转换为具有已定义行为的明确私有基类(C++标准对此进行例外处理),即使通常不会授予访问权限.然后还有朋友和班级本身可以自由转换.
约翰内斯的回答涵盖了基本事实.但还有一点.所以,考虑一下
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.
}
Run Code Online (Sandbox Code Playgroud)
当我编译时,我得到了,就像现在(在约翰内斯回答之后)你会期待的那样,
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(如果Base是纯接口的情况),或者Intermediate确实需要自己的Base子对象.
后一种情况,两个Base子对象,可能不是你想要的,但如果你想要那么那么一种治疗就是引入另一个中间类,比如说ResolvableBase.
喜欢:
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.
}
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,例如Base是一个接口,只需要一个Base子对象,您可以使用虚拟继承.
虚拟继承通常会增加一些运行时开销,而Visual C++并不太喜欢它.
但是它允许你"继承"接口的实现,比如在Java和C#中:
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.
}
Run Code Online (Sandbox Code Playgroud)
微妙:我更改了继承列表顺序,以避免g ++关于初始化顺序的愚蠢警告.
烦恼:Visual C++通过支配问题发布关于继承(实现)的愚蠢的C4250问题.这就像"警告:你正在使用标准的主要功能".哦,好吧,把它关掉.
干杯&hth.,