Saya ingin memiliki kelas dengan anggota data statis pribadi (vektor yang berisi semua karakter az). Dalam java atau C #, saya bisa membuat "static constructor" yang akan berjalan sebelum saya membuat instance kelas apa pun, dan mengatur anggota data statis kelas. Hanya dijalankan sekali (karena variabel hanya dibaca dan hanya perlu diatur sekali) dan karena ini merupakan fungsi dari kelas, ia dapat mengakses anggota privatnya. Saya bisa menambahkan kode dalam konstruktor yang memeriksa untuk melihat apakah vektor diinisialisasi, dan menginisialisasi jika tidak, tetapi itu memperkenalkan banyak pemeriksaan yang diperlukan dan sepertinya bukan solusi optimal untuk masalah tersebut.
Pikiran muncul pada saya bahwa karena variabel hanya akan dibaca, mereka hanya bisa menjadi public static const, jadi saya dapat mengaturnya sekali di luar kelas, tetapi sekali lagi, sepertinya semacam peretasan yang jelek.
Apakah mungkin untuk memiliki anggota data statis pribadi di kelas jika saya tidak ingin menginisialisasi mereka dalam konstruktor instance?
sumber
Jawaban:
Untuk mendapatkan yang setara dengan konstruktor statis, Anda perlu menulis kelas biasa yang terpisah untuk menampung data statis dan kemudian membuat contoh statis dari kelas biasa itu.
sumber
friend
banyak akal sehingga kelasElsewhere
dapat dengan mudah mengaksesStaticStuff
internal (tanpa merusak enkapsulasi dengan cara berbahaya, saya dapat menambahkan).Yah, Anda bisa
Jangan lupa (dalam .cpp) ini:
Program masih akan terhubung tanpa baris kedua, tetapi initializer tidak akan dieksekusi.
sumber
MyClass::a.push_back(i)
bukana.push_back(i)
?_initializer
adalah sebuah subobjek dariMyClass
. Subobyek diinisialisasi dalam urutan ini: subobjek kelas dasar virtual, dalam urutan-dalam, urutan kiri-ke-kanan (tetapi hanya menginisialisasi setiap sub-proyek yang berbeda sekali); kemudian sub-objek kelas dasar, dalam urutan pertama, kiri-ke-kanan; kemudian sub-proyek anggota dalam urutan deklarasi. Jadi aman menggunakan strategi EFraim, asalkan kode itu_initialiser
hanya merujuk pada anggota yang dideklarasikan sebelumnya.Solusi C ++ 11
Sejak C ++ 11, Anda cukup menggunakan ekspresi lambda untuk menginisialisasi anggota kelas statis. Ini bahkan berfungsi jika Anda perlu memaksakan urutan konstruksi antara berbagai anggota statis, atau jika Anda memiliki anggota statis
const
.File tajuk:
Sumber data:
sumber
try catch
blok jika pengecualian mungkin dilemparkan.Dalam file .h:
Dalam file .cpp:
sumber
Berikut adalah pendekatan lain yang mirip dengan Daniel Earwicker, juga menggunakan saran teman kelas Konrad Rudolph. Di sini kami menggunakan kelas utilitas teman dalam pribadi untuk menginisialisasi anggota statis kelas utama Anda. Sebagai contoh:
File tajuk:
File implementasi:
Pendekatan ini memiliki keuntungan menyembunyikan kelas Initializer dari dunia luar, menjaga agar semua yang ada dalam kelas diinisialisasi.
sumber
ToBeInitialized::Initializer::Initializer()
dipanggil, jadi Anda perlu menambahkanToBeInitialized::Initializer ToBeInitialized::initializer;
ke file implementasi. Saya mengambil beberapa hal dari ide Anda dan dari ide EFraim, dan itu berfungsi persis seperti yang saya butuhkan dan terlihat bersih. Terima kasih sobat.Test::StaticTest()
disebut tepat sekali selama inisialisasi global statis.Pemanggil hanya perlu menambahkan satu baris ke fungsi yang menjadi konstruktor statis mereka.
static_constructor<&Test::StaticTest>::c;
memaksa inisialisasic
selama inisialisasi statis global.sumber
Tidak perlu suatu
init()
fungsi,std::vector
dapat dibuat dari rentang:Perhatikan, bagaimanapun, bahwa statika tipe kelas menyebabkan masalah di perpustakaan, sehingga mereka harus dihindari di sana.
Pembaruan C ++ 11
Pada C ++ 11, Anda dapat melakukan ini sebagai gantinya:
Secara semantik setara dengan solusi C ++ 98 dalam jawaban asli, tetapi Anda tidak bisa menggunakan string literal di sisi kanan, jadi itu tidak sepenuhnya unggul. Namun, jika Anda memiliki vektor dari jenis lain dari
char
,wchar_t
,char16_t
atauchar32_t
(array yang dapat ditulis sebagai string literal), versi C ++ 11 ketat akan menghapus kode boilerplate tanpa memperkenalkan sintaks lainnya, dibandingkan dengan C ++ 98 Versi: kapan.sumber
Konsep konstruktor statis diperkenalkan di Jawa setelah mereka belajar dari masalah di C ++. Jadi kami tidak memiliki padanan langsung.
Solusi terbaik adalah dengan menggunakan tipe POD yang dapat diinisialisasi secara eksplisit.
Atau buat anggota statis Anda tipe tertentu yang memiliki konstruktor sendiri yang akan menginisialisasi dengan benar.
sumber
Ketika mencoba mengkompilasi dan menggunakan kelas
Elsewhere
(dari jawaban Earwicker ) saya mendapatkan:Tampaknya tidak mungkin untuk menginisialisasi atribut statis tipe non-integer tanpa meletakkan beberapa kode di luar definisi kelas (CPP).
Untuk membuat kompilasi itu, Anda dapat menggunakan " metode statis dengan variabel lokal statis di dalamnya ". Sesuatu seperti ini:
Dan Anda juga dapat meneruskan argumen ke konstruktor atau menginisialisasi dengan nilai-nilai spesifik, sangat fleksibel, kuat, dan mudah diterapkan ... satu-satunya adalah Anda memiliki metode statis yang berisi variabel statis, bukan atribut statis ... sintaksis sedikit berubah, tetapi masih bermanfaat. Semoga ini bermanfaat bagi seseorang,
Hugo González Castro.
sumber
Saya kira solusi sederhana untuk ini adalah:
sumber
Baru saja menyelesaikan trik yang sama. Saya harus menentukan definisi anggota statis tunggal untuk Singleton. Tetapi membuat segalanya menjadi lebih rumit - saya telah memutuskan bahwa saya tidak ingin memanggil ctor dari RandClass () kecuali saya akan menggunakannya ... itu sebabnya saya tidak ingin menginisialisasi singleton secara global dalam kode saya. Saya juga telah menambahkan antarmuka sederhana dalam kasus saya.
Ini kode terakhir:
Saya menyederhanakan kode dan menggunakan fungsi rand () dan satu-satunya initializer seed srand ()
sumber
Inilah varian solusi EFraim saya; perbedaannya adalah bahwa, berkat instantiasi templat implisit, konstruktor statis hanya dipanggil jika instance kelas dibuat, dan bahwa tidak ada definisi dalam
.cpp
file yang diperlukan (berkat keajaiban instantiasi templat).Dalam
.h
file, Anda memiliki:Dalam
.cpp
file tersebut, Anda dapat memiliki:Catatan yang
MyClass::a
diinisialisasi hanya jika baris [1] ada di sana, karena itu memanggil (dan membutuhkan instantiasi) konstruktor, yang kemudian memerlukan instantiasi_initializer
.sumber
Berikut metode lain, di mana vektor bersifat pribadi untuk file yang berisi implementasi dengan menggunakan namespace anonim. Ini berguna untuk hal-hal seperti tabel pencarian yang bersifat pribadi untuk implementasi:
sumber
I
dani
sesuatu yang sedikit lebih tidak jelas sehingga Anda tidak sengaja menggunakannya di tempat yang lebih rendah dalam file.Tentu saja tidak perlu serumit jawaban yang diterima saat ini (oleh Daniel Earwicker). Kelasnya berlebihan. Tidak perlu untuk perang bahasa dalam hal ini.
file .hpp:
file .cpp:
sumber
Penawaran GCC
https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html
Tag metode statis dengan atribut ini dan itu akan berjalan pada modul load, sebelum main ().
sumber
Anda mendefinisikan variabel anggota statis sama dengan cara Anda mendefinisikan metode anggota.
foo.h
foo.cpp
sumber
Untuk menginisialisasi variabel statis, Anda cukup melakukannya di dalam file sumber. Sebagai contoh:
sumber
Bagaimana dengan membuat template untuk meniru perilaku C #.
sumber
Untuk kasus sederhana seperti di sini variabel statis yang dibungkus dengan fungsi anggota statis hampir sama baiknya. Ini sederhana dan biasanya akan dioptimalkan oleh kompiler. Ini tidak memecahkan masalah urutan inisialisasi untuk objek kompleks sekalipun.
sumber
Apakah ini solusi?
sumber
Konstruktor statis dapat ditiru dengan menggunakan kelas teman atau kelas bersarang seperti di bawah ini.
Keluaran:
sumber
new
menggunakan array char hanya untuk segera membocorkan pointer dan menimpanya !?Wow, saya tidak percaya tidak ada yang menyebutkan jawaban yang paling jelas, dan yang paling mirip meniru perilaku statis-konstruktor C #, yaitu tidak dipanggil sampai objek pertama dari jenis itu dibuat.
std::call_once()
tersedia dalam C ++ 11; jika Anda tidak dapat menggunakannya, itu dapat dilakukan dengan variabel kelas boolean statis, dan operasi atom-bandingkan dan pertukaran. Di konstruktor Anda, lihat apakah Anda dapat mengubah secara statis flag kelas statis darifalse
menjaditrue
, dan jika demikian, Anda dapat menjalankan kode konstruksi statis.Untuk kredit tambahan, buatlah bendera 3 arah, bukan boolean, yaitu tidak berjalan, berlari, dan selesai berlari. Kemudian semua instance lain dari kelas itu dapat berputar-kunci sampai instance yang menjalankan static-constructor telah selesai (yaitu mengeluarkan memory-pagar, kemudian mengatur status ke "done running"). Spin-lock Anda harus menjalankan instruksi "jeda" prosesor, gandakan tunggu setiap kali hingga ambang, dll. - teknik spin-lock yang cukup standar.
Dengan tidak adanya C ++ 11, ini akan membantu Anda memulai.
Inilah beberapa kodesemu untuk memandu Anda. Masukkan ini dalam definisi kelas Anda:
Dan ini di konstruktor Anda:
sumber