Класс шаблона множественного наследования - PullRequest
7 голосов
/ 29 июля 2010
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.

Однако компилятор выдает мне следующую ошибку:

Могу ли я знать, почему существует двусмысленность? Разве не очевидно, что для 1-го вызова на передачу я хочу назвать сообщение А версией? Для 2-го подтверждения вызова, я хочу позвонить сообщениеB версии?


------ 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

Ответы [ 2 ]

11 голосов
/ 29 июля 2010

У меня сейчас нет компилятора, но я предполагаю, что одно наследство может скрыть другое: компилятор будет использовать Koenig Lookup , чтобы найти правильный символ, и, если я правильно помню, как только компилятор найдет подходящийсимвол (т. е. метод с именем submit), он прекратит поиск других в родительской и / или внешней областях.

В этом случае я думал, что оба наследующих класса будут искать символ, но безВаш точный компилятор (Visual C ++ 2003? 2008? 2010?), я не могу предположить намного больше.

После некоторых размышлений, другая возможность состоит в том, что компилятор нашел оба символа, но не может решить, какой из них вызвать (в этот момент разрешения символов компилятор заботится только об имени символа, а не о его точном прототипе).Я полагаю, что это последнее объяснение правильное.

Попробуйте добавить использование операторов в ваших производных классах:

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

, чтобы оба метода отправки были непосредственно в области действия класса A.

Также обратите внимание, что ваши методы отправки принимают сообщения как неконстантные ссылки, в то время как в конструкторе ваши параметры сообщений являются временными (и, следовательно, const r-значения).

Перезаписьглавное как:

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

может помочь компиляции (это может объяснить ошибку компилятора в строке 22).

Или вы можете изменить прототип ваших методов отправки, чтобы принимать ссылки на константы вместонеконстантные ссылки.

Примечание: все еще без компилятора, поэтому пытаюсь отладить ваш код ... :-P ...

1 голос
/ 29 июня 2012
Something* smth1 = ((Base<Something> *)d)->createBase<Something>();

Приведенный выше код работает нормально.

...