注册 登录
编程论坛 C++教室

多继承中的二义性问题

jfckpep 发布于 2011-07-24 13:49, 2149 次点击
using namespace std;
class Base
{
public:
    Base(int i):b(i) {cout<<"Base constructor. b="<<i<<endl;}
    ~Base(){cout<<"Base destructor. b="<<b<<endl;}
    int GetB(){return b;}
private:
    int b;
};

class Base11:virtual public Base
{
public:
    Base11(int i,int j):Base(i),b11(j)
    {
        cout<<"Base11 constructor."<<endl;
    }
    ~Base11(){cout<<"Base11 destructor."<<endl;}
    void Print()
    {
        cout<<"Data in Base11. b11="<<b11<<",b="<<GetB()<<endl;
    }
private:
    int b11;
};
class Base12:virtual public Base
{
public:
        Base12 (int i,int j):Base(i),b12(j)
    {
        cout<<"Base12 constructor.";
    }
        ~Base12(){cout<<"Base12 destructor."<<endl;}
        void Print()
        {
            cout<<"Data in Base12. b12="<<b12<<",b="<<GetB()<<endl;
        }
private:
    int b12;
};
class Base2:public  Base
{
public :
    Base2(int i,int j):Base(i),b2(j)
    {
        cout<<"Base2 constructor."<<endl;
    }
    ~Base2() {cout<<"Base2 destructor."<<endl;}
    void Print()
    {
        cout<<"Data in Base2. b2="<<b2<<",b="<<GetB()<<endl;
    }
private:
    int b2;
};
class Derived:public Base11,public Base12,public Base2
{
public:
    Derived(int i,int j,int k,int l,int m,int n,int x,int y):Base11(i,j),Base12(k,l),Base2(m,n),Base(x),d(y)
    {
        cout<<"Derived constructor."<<endl;
    }
    ~Derived(){cout<<"Derived destructor."<<endl;}
    int GetD(){return d;}
private:
    int d;
};

int main()
{
    Derived obj(1,2,3,4,5,6,7,8);
    obj.Base11::Print();
    obj.Base12::Print();
    obj.Base2::Print();
    cout<<"Data in itself. d="<<obj.GetD()<<endl;
    return 0;
}

这个程序是我教材里的一个例子,但是我编译时报错,出现了二义性,想了一下,的却是的,而书本却能给出了下面的输出结果,想问是怎么回事?
Base constructor. b=7
Base11 constructor.
Base12 constructor.
Base constructor. b=5
Base2 constructor.
Derived constructor.
Data in Base11. b11=2,b=7
Data in Base12. b12=4,b=7
Data in Base2. b2=6,b=5
Data in itself. d=8
...
11 回复
#2
specilize2011-07-24 19:21
不会啊,那里有二义性的,我试了下,完全正常运行啊
#3
jfckpep2011-07-24 21:23
回复 2楼 specilize
不会吧,我用的是vs2008和vs2010,都报错了ambiguous access of 'Base
#4
jfckpep2011-07-24 21:28
回复 2楼 specilize
类Derived从类Base11和Base12继承了成员GetB(),然后又从类Base2继承了GetB(),这不是二义性吗?
#5
rjsp2011-07-25 08:24
class Base2 : virtual public Base
#6
specilize2011-07-25 09:28
我在dev c++下测试这个程序没问题,在vs2008下就出现你说的那情况
我个人是觉得因为你在Drived类有对Base类进行构造,所以在Base11,Base12,Base2中对Base类的构造将被忽略,所以应该没有问题的,按照rjsp所说,Base类一旦成为虚基类,其他类只能虚继承于他吗?我也不太清楚,等待大家的讨论,学习学习。
另外,类Derived从类Base11和Base12继承了成员GetB(),然后又从类Base2继承了GetB(),这不是二义性吗? 楼主对二义性的理解有误,二义性不是这个意思,二义性是对调用来说的
#7
jfckpep2011-07-25 22:34
回复 5楼 rjsp
可是它的原意不是这个啊,它题目解释说的Base2不是虚对象
#8
jfckpep2011-07-25 22:38
回复 6楼 specilize
对啊,对GetB()访问时不就会出现二义性吗?
#9
lintaoyn2011-07-25 23:11
以下是引用rjsp在2011-7-25 08:24:50的发言:

class Base2 : virtual public Base
如果非要写class Base2 : public Base要什么解决基类的二义?标准上是什么说的?
如果定义和调用Base默认构造函数,就不会出现二义,为什么?
我查了资料,没能查到……
#10
langhuan2011-07-26 12:26
回复 楼主 jfckpep
貌似这个程序不存在二义性问题。
说说我的二义性的理解吧:二义性是指在一个多继承的类继承类中,包含了的基类有两个以上的基类成员中有相同的函数名和参数类型及个数。这样在主函数中,用继承类的对象来调用基类们共有的函数时,如果不用作用域分辨符时,就会因为编译系统不知道是那个基类的函数成员,而产生歧义,因此出现了二义性。
如:
#include<iostream>
using namespace std;
class A
{
public:
    A(int a);
    int geta();
private:
    int x;
};
A::A(int a)
{
    x=a;
}
int A::geta()
{
    return x;
}
class B
{
public:
    B(int b);
    int geta();
private:
    int x;
};
B::B(int b)
{
    x=b;
}
int B::geta()
{
    return x;
}
class C:public A,public B
{
public:
    C(int c,int d);
    int getC();
private:
    int y;
};
C::C(int c,int d):A(c),B(d)
{
    y=c;
}
int C::getC()
{
    return y;
}
int main()
{
    int a,b;
    a=8;
    b=3;
    C cc(a,b);
    cout<<cc.geta()<<"  "<<cc.geta()<<endl<<cc.getC()<<endl;//应该是: cout<<cc.geta()<<"  "<<cc.geta()<<endl<<cc.getC()<<endl;
    return 0;
}
#11
xg56992011-07-30 22:43
你基类的析构函数没有定义为虚析构函数virtual ~~Base(){};
其次将你的class Base2:public Base改为class Base2:virtual public Base就通过了

我对virtual的概念很不清,但只要碰到二义性问题加virtual就是王道,你的代码我看都没怎么看
在class Base2:public Base没加virtual的情况果断加上就通过

其实对于公共基类Base说明为虚基类的话那么只会派生Base中的一个函数了,不然base2派生出的子类会有base2类中的一个函数和Base类中的一个函数
从而2义了.

[ 本帖最后由 xg5699 于 2011-7-30 22:59 编辑 ]
#12
jfckpep2011-07-31 11:05
回复 11楼 xg5699
谁都知道改为class Base2:virtual public Base就可以通过了啊,只是这样改了就跟他题目想说的不一样了,另一个问题是没改前再VC6.0一样能编译通过
1