Gaya pengkodean saya termasuk idiom berikut:
class Derived : public Base
{
public :
typedef Base super; // note that it could be hidden in
// protected/private section, instead
// Etc.
} ;
Ini memungkinkan saya untuk menggunakan "super" sebagai alias ke Pangkalan, misalnya, dalam konstruktor:
Derived(int i, int j)
: super(i), J(j)
{
}
Atau bahkan ketika memanggil metode dari kelas dasar di dalam versinya yang ditimpa:
void Derived::foo()
{
super::foo() ;
// ... And then, do something else
}
Bahkan dapat dirantai (saya masih harus menemukan kegunaannya untuk itu):
class DerivedDerived : public Derived
{
public :
typedef Derived super; // note that it could be hidden in
// protected/private section, instead
// Etc.
} ;
void DerivedDerived::bar()
{
super::bar() ; // will call Derived::bar
super::super::bar ; // will call Base::bar
// ... And then, do something else
}
Lagi pula, saya menemukan penggunaan "typedef super" sangat berguna, misalnya, ketika Base adalah verbose dan / atau templated.
Faktanya adalah bahwa super diimplementasikan di Jawa, serta di C # (di mana ia disebut "basis", kecuali saya salah). Tetapi C ++ tidak memiliki kata kunci ini.
Jadi, pertanyaan saya:
- Apakah penggunaan typedef ini sangat umum / jarang / tidak pernah terlihat dalam kode yang Anda gunakan?
- apakah ini penggunaan typedef super Ok (yaitu apakah Anda melihat alasan kuat atau tidak begitu kuat untuk tidak menggunakannya)?
- haruskah "super" menjadi hal yang baik, haruskah itu dibakukan dalam C ++, atau apakah sudah cukup menggunakan typedef?
Sunting: Roddy menyebutkan fakta bahwa typedef harus bersifat pribadi. Ini berarti setiap kelas turunan tidak akan dapat menggunakannya tanpa mendeklarasikan ulang. Tapi saya kira itu juga akan mencegah rantai super :: super (tapi siapa yang akan menangis untuk itu?).
Sunting 2: Sekarang, beberapa bulan setelah menggunakan "super" secara besar-besaran, saya sepenuh hati setuju dengan sudut pandang Roddy: "super" harus bersifat pribadi. Saya akan mengangkat jawaban dua kali, tapi saya rasa saya tidak bisa.
sumber
super
kelihatannyaJava
dan itu tidak buruk, tapi ... TapiC++
mendukung banyak warisan.MyFirstBase<MyString, MyStruct<MyData, MyValue>>
mana-mana)template <class baz> struct Foo {...void bar() {...} ...}; struct Foo2: Foo<AnnoyinglyLongListOfArguments> { void bar2() { ... Foo::bar(); ...} };
Ini bekerja untuk saya dengan gcc 9.1 --std = c ++ 1y (c ++ 14).Jawaban:
Bjarne Stroustrup menyebutkan dalam Desain dan Evolusi C ++ bahwa
super
sebagai kata kunci dianggap oleh komite Standar ISO C ++ pertama kali C ++ distandarisasi.Dag Bruck mengusulkan ekstensi ini, menyebut kelas dasar "warisan." Proposal menyebutkan masalah pewarisan berganda, dan akan menandai penggunaan yang ambigu. Bahkan Stroustrup yakin.
Setelah diskusi, Dag Bruck (ya, orang yang sama yang membuat proposal) menulis bahwa proposal itu dapat diterapkan, secara teknis sehat, dan bebas dari kelemahan utama, dan menangani banyak warisan. Di sisi lain, tidak ada cukup uang untuk uang, dan komite harus menangani masalah yang lebih sulit.
Michael Tiemann datang terlambat, dan kemudian menunjukkan bahwa seorang super mengetik akan bekerja dengan baik, menggunakan teknik yang sama yang ditanyakan dalam posting ini.
Jadi, tidak, ini mungkin tidak akan pernah distandarisasi.
Jika Anda tidak memiliki salinan, Desain dan Evolusi sepadan dengan harga sampulnya. Salinan bekas bisa didapat sekitar $ 10.
sumber
typedef
teknik ini: tidak menghormati KERING. Satu-satunya cara adalah menggunakan makro jelek untuk mendeklarasikan kelas. Saat Anda mewarisi, basisnya bisa berupa kelas templat multi-parameter yang panjang, atau lebih buruk. (mis. multi-kelas) Anda harus menulis ulang semua itu untuk kedua kalinya. Akhirnya, saya melihat masalah besar dengan basis template yang memiliki argumen kelas template. Dalam hal ini super adalah templat (dan bukan instanciation templat). Yang tidak dapat diketikkan. Bahkan dalam C ++ 11 yang Anda butuhkanusing
untuk kasus ini.Saya selalu menggunakan "warisan" daripada super. (Mungkin karena latar belakang Delphi), dan saya selalu menjadikannya pribadi , untuk menghindari masalah ketika 'warisan' secara keliru dihilangkan dari suatu kelas tetapi subkelas mencoba menggunakannya.
'Templat kode' standar saya untuk membuat kelas baru termasuk typedef, jadi saya memiliki sedikit peluang untuk tidak sengaja menghilangkannya.
Saya tidak berpikir saran "super :: super" dirantai adalah ide yang bagus- Jika Anda melakukan itu, Anda mungkin terikat sangat keras pada hierarki tertentu, dan mengubahnya kemungkinan akan merusak barang-barang.
sumber
virtual
seperti yang ditunjukkan di sini: martinbroadhurst.com/typedef-super.htmlSatu masalah dengan ini adalah bahwa jika Anda lupa (kembali) mendefinisikan super untuk kelas turunan, maka setiap panggilan ke super :: sesuatu akan dikompilasi dengan baik tetapi mungkin tidak akan memanggil fungsi yang diinginkan.
Sebagai contoh:
(Seperti yang ditunjukkan oleh Martin York dalam komentar untuk jawaban ini, masalah ini dapat dihilangkan dengan membuat typedef bersifat pribadi daripada publik atau dilindungi.)
sumber
super1
untuk Base dansuper2
Berasal? DerivedAgain dapat menggunakan keduanya?FWIW Microsoft telah menambahkan ekstensi untuk __super dalam kompiler mereka.
sumber
Super (atau diwariskan) adalah Very Good Thing karena jika Anda perlu menempelkan lapisan pewarisan lain di antara Base dan Derived, Anda hanya perlu mengubah dua hal: 1. "class Base: foo" dan 2. the typedef
Jika saya ingat dengan benar, komite Standar C ++ sedang mempertimbangkan untuk menambahkan kata kunci untuk ini ... sampai Michael Tiemann menunjukkan bahwa trik typedef ini berfungsi.
Adapun warisan ganda, karena itu di bawah kendali programmer Anda dapat melakukan apa pun yang Anda inginkan: mungkin super1 dan super2, atau apa pun.
sumber
Saya baru saja menemukan solusi alternatif. Saya memiliki masalah besar dengan pendekatan typedef yang menggigit saya hari ini:
Jadi saya datang dengan solusi yang lebih baik menggunakan templat yang sangat sederhana.
Jadi sekarang, bukannya
kamu punya
Dalam hal ini,
BaseAlias
tidak bersifat pribadi dan saya sudah mencoba untuk menjaga terhadap penggunaan yang ceroboh dengan memilih nama jenis yang harus mengingatkan pengembang lain.sumber
public
alias adalah kelemahan, karena Anda terbuka terhadap bug yang disebutkan dalam jawaban Roddy dan Kristopher (mis. Anda dapat (secara tidak sengaja) berasal dariDerived
alih-alihMakeAlias<Derived>
)MakeAlias
atau penerusan yang sempurna, tetapi itu mengharuskan Anda untuk merujuk keMakeAlias<BaseAlias>
konstruktor daripada hanya merujuk keC
konstruktor secara langsung.)Saya tidak ingat pernah melihat ini sebelumnya, tetapi pada pandangan pertama saya menyukainya. Seperti yang dicatat Ferruccio , itu tidak bekerja dengan baik di hadapan MI, tetapi MI lebih merupakan pengecualian daripada aturan dan tidak ada yang mengatakan bahwa sesuatu harus digunakan di mana saja agar bermanfaat.
sumber
Saya telah melihat idiom ini digunakan dalam banyak kode dan saya cukup yakin saya bahkan pernah melihatnya di suatu tempat di perpustakaan Boost. Namun, sejauh yang saya ingat nama yang paling umum adalah
base
(atauBase
) bukansuper
.Ungkapan ini sangat berguna jika bekerja dengan kelas template. Sebagai contoh, pertimbangkan kelas berikut (dari proyek nyata ):
Jangan pedulikan nama yang lucu. Poin penting di sini adalah bahwa rantai pewarisan menggunakan argumen tipe untuk mencapai polimorfisme waktu kompilasi. Sayangnya, level bersarang dari template ini menjadi cukup tinggi. Oleh karena itu, singkatan sangat penting untuk keterbacaan dan pemeliharaan.
sumber
Saya sudah cukup sering melihatnya menggunakannya, kadang-kadang sebagai super_t, ketika basis adalah tipe template yang kompleks (
boost::iterator_adaptor
apakah ini, misalnya)sumber
Apakah penggunaan typedef ini sangat umum / jarang / tidak pernah terlihat dalam kode yang Anda gunakan?
Saya belum pernah melihat pola khusus ini dalam kode C ++ saya bekerja dengan, tetapi itu tidak berarti itu tidak ada di luar sana.
apakah ini penggunaan typedef super Ok (yaitu apakah Anda melihat alasan kuat atau tidak begitu kuat untuk tidak menggunakannya)?
Itu tidak memungkinkan pewarisan berganda (bersih, pokoknya).
haruskah "super" menjadi hal yang baik, haruskah itu dibakukan dalam C ++, atau apakah sudah cukup menggunakan typedef?
Untuk alasan yang dikutip di atas (multiple inheritance), no. Alasan mengapa Anda melihat "super" dalam bahasa lain yang Anda cantumkan adalah bahwa mereka hanya mendukung satu warisan, sehingga tidak ada kebingungan mengenai apa yang dimaksud "super". Memang, dalam bahasa-bahasa itu IS berguna tetapi tidak benar-benar memiliki tempat dalam model data C ++.
Oh, dan FYI: C ++ / CLI mendukung konsep ini dalam bentuk kata kunci "__super". Harap dicatat, bahwa C ++ / CLI juga tidak mendukung banyak pewarisan.
sumber
Salah satu alasan tambahan untuk menggunakan typedef untuk superclass adalah ketika Anda menggunakan templat kompleks dalam warisan objek.
Misalnya:
Di kelas B itu akan ideal untuk memiliki typedef untuk A kalau tidak, Anda akan terjebak mengulanginya di mana pun Anda ingin referensi anggota A.
Dalam kasus ini ia dapat bekerja dengan banyak pewarisan juga, tetapi Anda tidak akan memiliki typedef bernama 'super', itu akan disebut 'base_A_t' atau sesuatu seperti itu.
--jeffk ++
sumber
Setelah bermigrasi dari Turbo Pascal ke C ++ kembali pada hari itu, saya biasa melakukan ini untuk memiliki setara dengan kata kunci "turunan" Turbo Pascal, yang bekerja dengan cara yang sama. Namun, setelah pemrograman dalam C ++ selama beberapa tahun saya berhenti melakukannya. Saya menemukan saya hanya tidak membutuhkannya.
sumber
Saya tidak tahu apakah ini langka atau tidak, tetapi saya sudah melakukan hal yang sama.
Seperti yang telah ditunjukkan, kesulitan untuk membuat bagian dari bahasa itu sendiri adalah ketika sebuah kelas memanfaatkan pewarisan berganda.
sumber
Saya menggunakan ini dari waktu ke waktu. Tepat ketika saya menemukan diri saya mengetik tipe kelas dasar beberapa kali, saya akan menggantinya dengan typedef yang serupa dengan milik Anda.
Saya pikir ini bisa bermanfaat. Seperti yang Anda katakan, jika kelas dasar Anda adalah templat, ia dapat menyimpan pengetikan. Juga, kelas templat dapat mengambil argumen yang bertindak sebagai kebijakan untuk bagaimana templat seharusnya bekerja. Anda bebas mengubah jenis basis tanpa harus memperbaiki semua referensi Anda selama antarmuka basis tetap kompatibel.
Saya pikir penggunaan melalui typedef sudah cukup. Saya tidak bisa melihat bagaimana itu akan dibangun ke dalam bahasa itu karena multiple inheritence berarti ada banyak kelas dasar, jadi Anda bisa mengetiknya sesuai keinginan Anda untuk kelas yang menurut Anda logis adalah kelas dasar yang paling penting.
sumber
Saya mencoba memecahkan masalah yang sama persis ini; Saya melemparkan beberapa ide, seperti menggunakan templat variadic dan ekspansi paket untuk memungkinkan jumlah orang tua yang sewenang-wenang, tetapi saya menyadari bahwa akan menghasilkan implementasi seperti 'super0' dan 'super1'. Saya membuangnya karena itu akan lebih bermanfaat daripada tidak memulainya.
Solusi saya melibatkan kelas pembantu
PrimaryParent
dan diimplementasikan seperti itu:Kemudian kelas mana yang ingin Anda gunakan akan dinyatakan seperti itu:
Untuk menghindari perlunya menggunakan pewarisan virtual
PrimaryParent
padaBaseClass
, konstruktor yang mengambil sejumlah variabel argumen digunakan untuk memungkinkan pembangunanBaseClass
.Alasan di balik
public
warisanBaseClass
kePrimaryParent
adalah untukMyObject
memiliki kontrol penuh atas warisanBaseClass
meskipun memiliki kelas penolong di antara mereka.Ini berarti bahwa setiap kelas yang Anda inginkan
super
harus menggunakanPrimaryParent
kelas helper, dan setiap anak hanya dapat mewarisi dari satu kelas menggunakanPrimaryParent
(karenanya namanya).Batasan lain untuk metode ini, adalah
MyObject
dapat mewarisi hanya satu kelas yang mewarisi dariPrimaryParent
, dan bahwa seseorang harus diwarisi menggunakanPrimaryParent
. Inilah yang saya maksud:Sebelum Anda membuang ini sebagai opsi karena jumlah pembatasan yang tampaknya dan fakta ada kelas perantara antara setiap warisan, hal-hal ini tidak buruk.
Warisan berganda adalah alat yang kuat, tetapi dalam sebagian besar keadaan, hanya akan ada satu orang tua utama, dan jika ada orang tua lain, kemungkinan besar mereka adalah kelas Mixin, atau kelas yang tidak mewarisi dari mana pun
PrimaryParent
. Jika pewarisan berganda masih diperlukan (meskipun banyak situasi akan menguntungkan untuk menggunakan komposisi untuk mendefinisikan objek daripada pewarisan), daripada hanya secara eksplisit mendefinisikansuper
di kelas itu dan tidak mewarisi dariPrimaryParent
.Gagasan harus mendefinisikan
super
di setiap kelas tidak terlalu menarik bagi saya, menggunakanPrimaryParent
memungkinkansuper
, jelas alias berbasis warisan, untuk tetap berada di garis definisi kelas, bukan badan kelas di mana data harus pergi.Mungkin itu hanya aku.
Tentu saja setiap situasi berbeda, tetapi pertimbangkan hal-hal ini yang saya katakan ketika memutuskan opsi mana yang akan digunakan.
sumber
Saya tidak akan mengatakan banyak kecuali kode sekarang dengan komentar yang menunjukkan bahwa super tidak berarti memanggil basis!
super != base.
Singkatnya, apa yang dimaksud dengan "super"? lalu apa artinya "basis"?
2 aturan ini berlaku untuk typedef di kelas.
Pertimbangkan implementor perpustakaan dan pengguna perpustakaan, siapa yang super dan siapa yang basis?
untuk info lebih lanjut di sini adalah kode kerja untuk copy paste ke IDE Anda:
Poin penting lain di sini adalah ini:
di dalam
main()
kita menggunakan down panggilan polimorfik yang super panggilan ke atas, tidak benar-benar berguna dalam kehidupan nyata, tetapi menunjukkan perbedaannya.sumber
Saya menggunakan kata kunci __super. Tapi ini spesifik Microsoft:
http://msdn.microsoft.com/en-us/library/94dw1w7x.aspx
sumber
Ini adalah metode yang saya gunakan yang menggunakan makro, bukan typedef. Saya tahu bahwa ini bukan cara C ++ dalam melakukan sesuatu tetapi bisa lebih nyaman ketika merantai iterator bersama-sama melalui warisan ketika hanya kelas dasar terjauh dalam hirarki yang bertindak berdasarkan offset yang diwarisi.
Sebagai contoh:
Setup generik yang saya gunakan membuatnya sangat mudah untuk membaca dan menyalin / menempel di antara pohon warisan yang memiliki kode duplikat tetapi harus diganti karena jenis kembali harus sesuai dengan kelas saat ini.
Orang dapat menggunakan huruf kecil
super
untuk mereplikasi perilaku yang terlihat di Jawa tetapi gaya pengkodean saya adalah dengan menggunakan semua huruf besar untuk makro.sumber