Multiple Inheritance Template Class
Asked Answered
F

2

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());
}

My first thought is, the above code should be fine, as class A will contains 2 overloaded submit functions, which will accept messageA and messageB object.

However, the compiler gives me the following error :

May I know why there is an ambiguous? Isn't it is quite obvious that, for the 1st submit call, I want to call messageA version? For the 2nd submit call, I want to call messageB version?


------ 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
Flipper answered 29/7, 2010 at 9:5 Comment(1)
Note that the implicit conversion from messageA to messageA& is not standard C++; a non-const reference can only be bound to an lvalue (msdn.microsoft.com/en-us/library/186yxbac(VS.80).aspx). The submit() function should accept const T& rather than T&.Coreen
M
11

I have no compiler right now, but I guess one inheritance could hide the other : The compiler will use Koenig Lookup to find the right symbol, and if I remember correctly, once the compiler find a suitable symbol (i.e., a method called "submit"), it will stop searching for others in parent and/or outer scopes.

In this case, I thought both inheriting classes would be searched for the symbol, but without your exact compiler (Visual C++ 2003 ? 2008 ? 2010 ?), I cannot guess much more.

After some thoughts, another possibility is that the compiler did find both symbols, but is unable to decide which to call (at that moment of symbol resolution, the compiler cares only for symbol name, not its exact prototype). I believe this last explanation to be the right one.

Try adding using statements in your derived classes :

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

to bring both the submit methods directly in the A class scope.

Note, too, that your submit methods are taking messages as non-const reference, while in the constructor, your message parameters are temporaries (and thus, const r-values).

Re-writting the main as:

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

could help compile (this could explain the compiler error on line 22).

Or you could change the prototype of your submit methods to accept const references instead of non-const references.

Note: Still without compiler, so trying to brain-debug your code... :-P ...

Memorialize answered 29/7, 2010 at 9:10 Comment(3)
"I guess one inheritance could hide the other" Nope. "The compiler will use Koenig Lookup" No, it won't. "the compiler did find both symbols, but is unable to decide which to call" Yes.Exhort
"temporaries (and thus, const r-values)." No, temporaries are not constant.Exhort
@Exhort It's much better to edit the question to improve it, instead of commenting "no" and "yes" to different quotes from it. Some may miss the comments.Michele
P
1
Something* smth1 = ((Base<Something> *)d)->createBase<Something>();

The above code works fine.

Positively answered 29/6, 2012 at 9:5 Comment(1)
"((Base<Something> *)d)" Ugly and very dangerous: you would hide a serious type issue with this C-style cast. OTOH, this Base<Something>& dBase = *d; dBase.createBase<Something>(); is safe.Exhort

© 2022 - 2024 — McMap. All rights reserved.