У меня есть два базовых класса с использованием предложений
class MultiCmdQueueCallback {
using NetworkPacket = Networking::NetworkPacket;
....
}
class PlcMsgFactoryImplCallback {
using NetworkPacket = Networking::NetworkPacket;
....
}
Затем я объявляю класс
class PlcNetwork :
public RouterCallback,
public PlcMsgFactoryImplCallback,
public MultiCmdQueueCallback {
private:
void sendNetworkPacket(const NetworkPacket &pdu);
}
затем компилятор помечает ссылку на ошибку «NetworkPacket» неоднозначно «sendNetworkPacket (NetworkPacket & ...»
Теперь оба «использующих предложения» относятся к одному базовому классу Networking: NetworkPacket
и фактически, если я заменю объявление метода на:
void sendNetworkPacket(const Networking::NetworkPacket &pdu);
он компилируется нормально.
Почему компилятор рассматривает каждое предложение using как отдельный тип, даже если они оба указывают на один и тот же базовый тип. Это предписано стандартом или у нас есть ошибка компилятора?
c++
using-declaration
Эндрю Гёдхарт
источник
источник
NetworkPacket
- в MultiCmdQueueCallback, в PlcMsgFactoryImplCallback, в сети. Какой из них использовать, следует указать. И я не думаю, чтоvirtual
здесь может помочь помощь.Ответы:
Перед просмотром псевдонима результирующий тип (и доступность)
мы смотрим на имена
и действительно,
NetworkPacket
возможноMultiCmdQueueCallback::NetworkPacket
PlcMsgFactoryImplCallback::NetworkPacket
То, на что они оба указывают, не
Networking::NetworkPacket
имеет значения.Мы делаем разрешение имени, что приводит к неоднозначности.
источник
error: [...] is private within this context
.class A { public: void f(char, int) { } private: void f(int, char) { } }; void demo() { A a; a.f('a', 'd'); }
- не то же самое, но разрешение перегрузки работает одинаково: учитывайте все доступные функции, только после выбора подходящей учитывайте доступность ... В данном случае вы также получаете неоднозначность; если вы измените приватную функцию, чтобы она принимала два символа, она будет выбрана, хотя и частной, и вы столкнетесь с следующей ошибкой компиляции.Вы можете просто устранить неоднозначность, вручную выбрав, какой из них вы хотите использовать.
Компилятор ищет только определения в базовых классах. Если в обоих базовых классах присутствует один и тот же тип и / или псевдоним, он просто жалуется, что не знает, какой из них использовать. Неважно, будет ли результирующий тип одинаковым или нет.
Компилятор ищет имена только на первом шаге, полностью независимый, если это имя является функцией, типом, псевдонимом, методом или чем-то еще. Если имена неоднозначны, компилятор не предпринимает никаких дальнейших действий! Он просто жалуется с сообщением об ошибке и останавливается. Так что просто разрешите неоднозначность с помощью данного оператора using.
источник
Из документов :
Хотя эти два
using
предложения представляют один и тот же тип, у компилятора есть два варианта в следующей ситуации:Можно выбрать между:
MultiCmdQueueCallback::NetworkPacket
а такжеPlcMsgFactoryImplCallback::NetworkPacket
потому что он наследует от обоих
MultiCmdQueueCallback
иPlcMsgFactoryImplCallback
базовых классов. Результатом разрешения имени компилятора является ошибка неоднозначности, которая у вас есть. Чтобы это исправить, вам нужно явно указать компилятору использовать тот или иной код:или
источник
class C { void f(uint32_t); }; void C::f(unsigned int) { }
(при условии совпадения псевдонима). Так почему здесь разница? Они по-прежнему относятся к тому же типу, что подтверждается вашей цитатой (которую я не считаю достаточной для объяснения) ...class C : public A, public B { void f(A::D); }; void C::f(B::D) { }
- по крайней мере, GCC принимает.Есть две ошибки:
частный частный
Я не вижу проблемы, когда компилятор сначала жалуется на вторую проблему, потому что порядок на самом деле не имеет значения - вы должны исправить обе проблемы, чтобы продолжить.
государственно-общественного
Если вы измените видимость обоих
MultiCmdQueueCallback::NetworkPacket
иPlcMsgFactoryImplCallback::NetworkPacket
либо на общедоступные, либо на защищенные, то вторая проблема (неоднозначность) очевидна - это два псевдонима разных типов, хотя они имеют один и тот же базовый тип данных. Некоторые могут подумать, что «умный» компилятор может решить эту проблему (конкретный случай), но имейте в виду, что компилятор должен «мыслить в общем» и принимать решения на основе глобальных правил, а не делать исключения для конкретного случая. Представьте себе следующий случай:Должен ли компилятор относиться к обоим
NetworkPacketID
одинаково? Точно нет. Потому что в 32-битной системеsize_t
она 32-битная, аuint64_t
всегда 64-битная. Но если мы хотим, чтобы компилятор проверял базовые типы данных, он не мог бы различить их в 64-битной системе.государственно-частного
Я полагаю, что этот пример не имеет никакого смысла в сценарии использования OP, но так как здесь мы решаем проблемы в целом, давайте рассмотрим, что:
Я думаю, что в этом случае компилятор должен рассматривать
PlcNetwork::NetworkPacket
как,PlcMsgFactoryImplCallback::NetworkPacket
потому что у него нет других вариантов. Почему он до сих пор отказывается это сделать и обвиняет в неопределенности, для меня загадка.источник