Saya memiliki dua kelas dasar dengan menggunakan klausa
class MultiCmdQueueCallback {
using NetworkPacket = Networking::NetworkPacket;
....
}
class PlcMsgFactoryImplCallback {
using NetworkPacket = Networking::NetworkPacket;
....
}
Saya kemudian mendeklarasikan sebuah kelas
class PlcNetwork :
public RouterCallback,
public PlcMsgFactoryImplCallback,
public MultiCmdQueueCallback {
private:
void sendNetworkPacket(const NetworkPacket &pdu);
}
kompiler kemudian menandai rujukan kesalahan ke 'NetworkPacket' adalah ambigu 'sendNetworkPacket (NetworkPacket & ...'
Sekarang keduanya 'menggunakan klausa' untuk kelas jaringan yang sama: NetworkPacket
dan sebenarnya jika saya mengganti deklarasi metode dengan:
void sendNetworkPacket(const Networking::NetworkPacket &pdu);
itu mengkompilasi dengan baik.
Mengapa kompiler memperlakukan masing-masing menggunakan klausa sebagai tipe yang berbeda walaupun keduanya menunjuk ke tipe dasar yang sama. Apakah ini diamanatkan oleh standar atau apakah kita memiliki bug penyusun?
c++
using-declaration
Andrew Goedhart
sumber
sumber
NetworkPacket
- di MultiCmdQueueCallback, di PlcMsgFactoryImplCallback, di Networking. Yang mana yang harus digunakan harus ditentukan. Dan saya tidak berpikir menempatkanvirtual
akan membantu di sini.Jawaban:
Sebelum melihat alias jenis yang dihasilkan, (dan aksesibilitas)
kita melihat nama
dan memang,
NetworkPacket
mungkinMultiCmdQueueCallback::NetworkPacket
PlcMsgFactoryImplCallback::NetworkPacket
Fakta yang mereka berdua tunjukkan
Networking::NetworkPacket
tidak relevan.Kami melakukan resolusi nama depan, yang menghasilkan ambiguitas.
sumber
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'); }
- tidak sama, tetapi resolusi kelebihan bekerja sama: Pertimbangkan semua fungsi yang tersedia, hanya setelah memilih yang tepat, pertimbangkan aksesibilitas ... Dalam kasus yang diberikan, Anda juga mendapatkan ambiguitas; jika Anda mengubah fungsi privat untuk menerima dua karakter, itu akan dipilih meskipun bersifat pribadi - dan Anda mengalami kesalahan kompilasi berikutnya.Anda cukup dapat menyelesaikan ambiguitas dengan memilih secara manual mana yang ingin Anda gunakan.
Kompilator hanya mencari definisi di kelas dasar. Jika jenis dan atau alias yang sama ada di kedua kelas dasar itu hanya mengeluh bahwa ia tidak tahu mana yang harus digunakan. Tidak masalah apakah tipe yang dihasilkan sama atau tidak.
Kompilator hanya mencari nama di langkah pertama, sepenuhnya independen jika nama ini adalah fungsi, tipe, alias, metode atau apa pun. Jika nama tidak jelas, tidak ada tindakan lebih lanjut yang dilakukan dari kompiler! Itu hanya mengeluh dengan pesan kesalahan dan berhenti. Jadi cukup selesaikan ambiguitas dengan pernyataan menggunakan yang diberikan.
sumber
Dari dokumen :
Meskipun, kedua
using
klausa tersebut mewakili tipe yang sama, kompiler memiliki dua pilihan dalam situasi berikut:Itu dapat memilih antara:
MultiCmdQueueCallback::NetworkPacket
danPlcMsgFactoryImplCallback::NetworkPacket
karena mewarisi dari keduanya
MultiCmdQueueCallback
PlcMsgFactoryImplCallback
kelas dasar dan . Hasil dari resolusi nama kompiler adalah kesalahan ambiguitas yang Anda miliki. Untuk memperbaikinya, Anda perlu secara eksplisit menginstruksikan kompiler untuk menggunakan satu atau yang lain seperti ini:atau
sumber
class C { void f(uint32_t); }; void C::f(unsigned int) { }
(asalkan alias cocok). Jadi mengapa ada perbedaan di sini? Mereka masih tipe yang sama, dikonfirmasi oleh kutipan Anda (yang saya pikir tidak cukup untuk menjelaskan) ...class C : public A, public B { void f(A::D); }; void C::f(B::D) { }
- setidaknya GCC menerima.Ada dua kesalahan:
pribadi-pribadi
Saya tidak melihat masalah yang dikompilasi oleh kompiler tentang masalah kedua terlebih dahulu karena urutannya tidak terlalu penting - Anda harus memperbaiki kedua masalah untuk melanjutkan.
publik-publik
Jika Anda mengubah visibilitas keduanya
MultiCmdQueueCallback::NetworkPacket
danPlcMsgFactoryImplCallback::NetworkPacket
menjadi publik atau dilindungi, maka masalah kedua (ambiguitas) jelas - keduanya adalah dua jenis alias yang berbeda meskipun keduanya memiliki tipe data dasar yang sama. Beberapa orang mungkin berpikir bahwa kompiler "pintar" dapat menyelesaikan ini (kasus khusus) untuk Anda, tetapi perlu diingat bahwa kompiler perlu "berpikir secara umum" dan membuat keputusan berdasarkan aturan global alih-alih membuat pengecualian spesifik kasus. Bayangkan kasus berikut:Haruskah kompiler memperlakukan keduanya
NetworkPacketID
sama? Tentu tidak. Karena pada sistem 32-bit, sementarasize_t
32-bituint64_t
selalu 64-bit. Tetapi jika kita ingin kompiler memeriksa tipe data yang mendasarinya, maka kompiler itu tidak dapat membedakannya pada sistem 64-bit.privasi Umum
Saya percaya contoh ini tidak masuk akal dalam kasus penggunaan OP, tetapi karena di sini kita sedang memecahkan masalah secara umum, mari kita pertimbangkan bahwa:
Saya pikir dalam hal ini compiler harus memperlakukan
PlcNetwork::NetworkPacket
sepertiPlcMsgFactoryImplCallback::NetworkPacket
karena tidak memiliki choises lain. Mengapa ia masih menolak untuk melakukannya dan menyalahkan ambiguitas adalah sebuah misteri bagi saya.sumber