【问题标题】:Multiple Inheritance Template Class多继承模板类
【发布时间】:2011-03-22 14:42:37
【问题描述】:
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 个重载的提交函数,它们将接受 messageA 和 messageB 对象。

但是,编译器给了我以下错误:

我可以知道为什么会有歧义吗?对于第一次提交调用,我想调用 messageA 版本不是很明显吗?对于第二次提交调用,我想调用 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

【问题讨论】:

标签: c++ multiple-inheritance ambiguous name-lookup class-members


【解决方案1】:

我现在没有编译器,但我猜一个继承可以隐藏另一个:编译器将使用Koenig Lookup 来找到正确的符号,如果我没记错的话,一旦编译器找到合适的符号(即方法称为“提交”),它将停止在父和/或外部范围内搜索其他人。

在这种情况下,我认为会在两个继承类中搜索符号,但如果没有您的确切编译器(Visual C++ 2003 ? 2008 ? 2010 ?),我无法猜测更多。

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

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

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

将两个提交方法直接带入 A 类范围。

还要注意,您的提交方法将消息作为非常量引用,而在构造函数中,您的消息参数是临时的(因此是 const r-values)。

将主要重写为:

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

可以帮助编译(这可以解释第 22 行的编译器错误)。

或者您可以更改提交方法的原型以接受 const 引用而不是非 const 引用。

注意:仍然没有编译器,因此尝试对您的代码进行大脑调试... :-P ...

【讨论】:

  • "我猜一个继承可以隐藏另一个" 不。 "编译器将使用 Koenig Lookup" 不,它不会。 “编译器确实找到了这两个符号,但无法决定调用哪个符号”是的。
  • "临时变量(因此是 const r-values)。" 不,临时变量不是恒定的。
【解决方案2】:
Something* smth1 = ((Base<Something> *)d)->createBase<Something>();

上面的代码运行良好。

【讨论】:

  • "((Base&lt;Something&gt; *)d)" 丑陋且非常危险:你会用这种 C 风格的演员表隐藏一个严重的类型问题。 OTOH,这个Base&lt;Something&gt;&amp; dBase = *d; dBase.createBase&lt;Something&gt;(); 是安全的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-23
  • 2013-01-09
  • 2018-01-18
  • 2012-10-05
  • 1970-01-01
相关资源
最近更新 更多