Eu tenho duas classes base com cláusulas de uso
class MultiCmdQueueCallback {
using NetworkPacket = Networking::NetworkPacket;
....
}
class PlcMsgFactoryImplCallback {
using NetworkPacket = Networking::NetworkPacket;
....
}
Declaro uma classe
class PlcNetwork :
public RouterCallback,
public PlcMsgFactoryImplCallback,
public MultiCmdQueueCallback {
private:
void sendNetworkPacket(const NetworkPacket &pdu);
}
o compilador sinaliza uma referência de erro para 'NetworkPacket' é ambígua 'sendNetworkPacket (NetworkPacket & ...'
Agora, ambas as 'cláusulas de uso' resolvem a mesma classe subjacente Rede: NetworkPacket
e, de fato, se eu substituir a declaração do método por:
void sendNetworkPacket(const Networking::NetworkPacket &pdu);
compila bem.
Por que o compilador trata cada cláusula de uso como um tipo distinto, embora ambos apontem para o mesmo tipo subjacente. Isso é obrigatório pelo padrão ou temos um bug do compilador?
c++
using-declaration
Andrew Goedhart
fonte
fonte
NetworkPacket
- no MultiCmdQueueCallback, em PlcMsgFactoryImplCallback, em Rede. Qual usar deve ser especificado. E eu não acho que colocarvirtual
aqui será de alguma ajuda.Respostas:
Antes de analisar o tipo resultante de alias, (e acessibilidade)
olhamos para nomes
e realmente,
NetworkPacket
pode serMultiCmdQueueCallback::NetworkPacket
PlcMsgFactoryImplCallback::NetworkPacket
O fato de ambos apontarem
Networking::NetworkPacket
é irrelevante.Nós fazemos a resolução do primeiro nome, o que resulta em ambiguidade.
fonte
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'); }
- não é o mesmo, mas a resolução de sobrecarga funciona da mesma forma: considere todas as funções disponíveis; somente depois de selecionar a apropriada, considere a acessibilidade ... Nesse caso, você também obtém ambiguidade; se você alterar a função privat para aceitar dois caracteres, ela será selecionada, embora seja privada - e você encontrará o próximo erro de compilação.Você pode resolver a ambiguidade simplesmente selecionando manualmente qual deseja usar.
O compilador procura apenas as definições nas classes base. Se o mesmo tipo e ou alias estiver presente nas duas classes base, ele simplesmente reclama que não sabe qual usar. Não importa se o tipo resultante é o mesmo ou não.
O compilador procura apenas nomes na primeira etapa, totalmente independente se esse nome for uma função, tipo, alias, método ou qualquer outra coisa. Se os nomes forem ambíguos, nenhuma ação adicional será feita a partir do compilador! Simplesmente reclama com a mensagem de erro e para. Portanto, basta resolver a ambiguidade com a instrução using fornecida.
fonte
Dos documentos :
Embora essas duas
using
cláusulas representem o mesmo tipo, o compilador tem duas opções na seguinte situação:Pode escolher entre:
MultiCmdQueueCallback::NetworkPacket
ePlcMsgFactoryImplCallback::NetworkPacket
porque herda das classes base
MultiCmdQueueCallback
ePlcMsgFactoryImplCallback
. Um resultado da resolução de nomes do compilador é o erro de ambiguidade que você possui. Para corrigir isso, você precisa instruir explicitamente o compilador a usar um ou outro como este:ou
fonte
class C { void f(uint32_t); }; void C::f(unsigned int) { }
(desde que o alias corresponda). Então, por que uma diferença aqui? Eles ainda são do mesmo tipo, confirmado por sua citação (que não considero suficiente para explicar) ...class C : public A, public B { void f(A::D); }; void C::f(B::D) { }
- pelo menos o GCC aceita.Existem dois erros:
privado-privado
Não vejo um problema que o compilador reclame primeiro sobre o segundo problema, porque o pedido realmente não importa - é necessário corrigir os dois problemas para prosseguir.
público-público
Se você alterar a visibilidade de ambos
MultiCmdQueueCallback::NetworkPacket
ePlcMsgFactoryImplCallback::NetworkPacket
para público ou protegido, o segundo problema (ambiguidade) é óbvio - esses são dois aliases de tipo diferentes, embora tenham o mesmo tipo de dados subjacente. Alguns podem pensar que um compilador "inteligente" pode resolver isso (um caso específico) para você, mas lembre-se de que o compilador precisa "pensar em geral" e tomar decisões com base em regras globais em vez de fazer exceções específicas a cada caso. Imagine o seguinte caso:O compilador deve tratar
NetworkPacketID
os mesmos? Claro que não. Porque em um sistema de 32 bits, elesize_t
é de 32 bits euint64_t
sempre de 64 bits. Mas, se quisermos que o compilador verifique os tipos de dados subjacentes, não será possível diferenciá-los em um sistema de 64 bits.público Privado
Acredito que este exemplo não faz sentido no caso de uso do OP, mas como aqui estamos resolvendo problemas em geral, vamos considerar o seguinte:
Penso que, neste caso, o compilador deve tratar
PlcNetwork::NetworkPacket
comoPlcMsgFactoryImplCallback::NetworkPacket
se não tivesse outras opções. Por que ainda se recusa a fazê-lo e culpa pela ambiguidade é um mistério para mim.fonte