多重继承模板类

7
class messageA {
};

class messageB {
};

template<class T>
class queue {
public:
    virtual ~queue() {}
    void submit(T& x) {}
};

class A : public queue<messageA>, public queue<messageB>
{
};

int main()
{
    A aa;
    aa.submit(messageA());
    aa.submit(messageB());
}

我的第一个想法是,上面的代码应该没问题,因为类A将包含2个重载的submit函数,它们将接受messageA和messageB对象。

然而,编译器给我以下错误:

我能知道为什么会出现歧义吗?难道不很明显吗,对于第一个submit调用,我想调用messageA版本?对于第二个submit调用,我想调用messageB版本?


------ Build started: Project: main, Configuration: Release Win32 ------
Compiling...
main.cpp
.\main.cpp(21) : error C2385: ambiguous access of 'submit'
        could be the 'submit' in base 'queue<messageA>'
        or could be the 'submit' in base 'queue<messageB>'
.\main.cpp(21) : error C3861: 'submit': identifier not found
.\main.cpp(22) : error C2385: ambiguous access of 'submit'
        could be the 'submit' in base 'queue<messageA>'
        or could be the 'submit' in base 'queue<messageB>'
.\main.cpp(22) : error C2664: 'queue<T>::submit' : cannot convert parameter 1 from 'messageB' to 'messageA &'
        with
        [
            T=messageA
        ]
.\main.cpp(22) : error C3861: 'submit': identifier not found

请注意,从 messageAmessageA& 的隐式转换不是标准的 C++;非 const 引用只能绑定到左值 (http://msdn.microsoft.com/en-us/library/186yxbac(VS.80).aspx)。`submit()` 函数应该接受 const T& 而不是 T& - In silico
2个回答

12

目前我没有编译器,但我猜想继承中的一个可能会隐藏另一个:编译器将使用Koenig Lookup查找正确的符号,并且如果我记得正确的话,一旦编译器找到合适的符号(即名为“submit”的方法),它就会停止在父类和/或外部作用域中搜索其他符号。

在这种情况下,我认为两个继承类都将搜索该符号,但是如果没有你准确的编译器(Visual C++ 2003?2008?2010?),我就无法猜测更多了。

经过一些思考,另一个可能性是编译器确实找到了两个符号,但无法确定调用哪一个(在符号解析的那一刻,编译器只关心符号名称,而不是它的确切原型)。我相信这个最后的解释是正确的。

尝试在派生类中添加using语句:

class A : public queue<messageA>, public queue<messageB>
{
   using queue<messageA>::submit ;
   using queue<messageB>::submit ;
} ;

将提交方法直接放在A类范围内。

注意,你的提交方法采用非const引用的消息参数,而在构造函数中,你的消息参数是暂时对象(即const右值引用)。

将主代码重写为:

int main()
{
    A aa;
    messageA mA ;
    messageA mB ;
    aa.submit(mA);
    aa.submit(mB);
}

可以尝试编译一下(这可能可以解释第22行的编译器错误)。

或者你可以将submit方法的原型更改为接受const引用而不是非const引用。

注意:还没有编译器,所以正在尝试脑力调试您的代码... :-P ...


"我猜一个继承可能会隐藏另一个" 不对。 "编译器将使用Koenig查找" 不,它不会。 "编译器确实找到了这两个符号,但无法决定调用哪一个" 是的。 - curiousguy
临时变量(因此,const r-values)是不是常量。 - curiousguy

1
Something* smth1 = ((Base<Something> *)d)->createBase<Something>();

上述代码运行良好。


"((Base<Something> *)d)" 这是丑陋而非常危险的:您将使用这种 C 风格的转换隐藏了一个严重的类型问题。另一方面,Base<Something>& dBase = *d; dBase.createBase<Something>(); 是安全的。 - curiousguy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接