Apa cara terbaik untuk menginisialisasi anggota data pribadi yang statis di C ++? Saya mencoba ini di file header saya, tetapi itu memberi saya kesalahan linker aneh:
class foo
{
private:
static int i;
};
int foo::i = 0;
Saya kira ini karena saya tidak dapat menginisialisasi anggota pribadi dari luar kelas. Jadi apa cara terbaik untuk melakukan ini?
c++
initialization
static-members
Jason Baker
sumber
sumber
inline static int x[] = {1, 2, 3};
. Lihat en.cppreference.com/w/cpp/language/static#Static_data_membersJawaban:
Deklarasi kelas harus di file header (Atau di file sumber jika tidak dibagikan).
File: foo.h
Tetapi inisialisasi harus dalam file sumber.
File: foo.cpp
Jika inisialisasi ada dalam file header maka setiap file yang menyertakan file header akan memiliki definisi anggota statis. Jadi selama fase tautan Anda akan mendapatkan kesalahan tautan karena kode untuk menginisialisasi variabel akan didefinisikan dalam beberapa file sumber. Inisialisasi
static int i
harus dilakukan di luar fungsi apa pun.Catatan: Matt Curtis: poin bahwa C ++ memungkinkan penyederhanaan di atas jika statis variabel anggota adalah const tipe int (misalnya
int
,bool
,char
). Anda kemudian dapat mendeklarasikan dan menginisialisasi variabel anggota langsung di dalam deklarasi kelas di file header:sumber
Untuk variabel :
foo.h:
foo.cpp:
Ini karena hanya ada satu contoh
foo::i
dalam program Anda. Ini semacam setaraextern int i
dalam file header danint i
file sumber.Untuk konstanta, Anda bisa meluruskan nilainya dalam deklarasi kelas:
sumber
private
variabel dapat diinisialisasi di luar Kelas di sini, dapatkah ini dilakukan untuk variabel non-statis juga.Class
tidak masuk akal dalam Cpp.Sejak C ++ 17, anggota statis dapat didefinisikan di header dengan kata kunci inline .
http://en.cppreference.com/w/cpp/language/static
"Anggota data statis dapat dinyatakan inline. Anggota data statis inline dapat didefinisikan dalam definisi kelas dan dapat menentukan penginisialisasi anggota default. Itu tidak memerlukan definisi di luar kelas:"
sumber
Untuk pemirsa pertanyaan ini di masa depan, saya ingin menunjukkan bahwa Anda harus menghindari apa yang disarankan oleh monkey0506 .
File header adalah untuk deklarasi.
File header dikompilasi satu kali untuk setiap
.cpp
file yang secara langsung atau tidak langsung#includes
, dan kode di luar fungsi apa pun dijalankan pada inisialisasi program, sebelumnyamain()
.Dengan memasukkan:
foo::i = VALUE;
ke dalam header,foo:i
akan diberikan nilaiVALUE
(apa pun itu) untuk setiap.cpp
file, dan penugasan ini akan terjadi dalam urutan yang tidak ditentukan (ditentukan oleh tautan) sebelummain()
dijalankan.Bagaimana jika kita
#define VALUE
menjadi nomor yang berbeda di salah satu.cpp
file kita ? Ini akan dikompilasi dengan baik dan kita tidak akan tahu mana yang menang sampai kita menjalankan program.Jangan pernah memasukkan kode yang dieksekusi ke header karena alasan yang sama bahwa Anda tidak pernah
#include
memiliki.cpp
file.termasuk penjaga (yang saya setuju Anda harus selalu gunakan) melindungi Anda dari sesuatu yang berbeda: header yang sama secara tidak langsung
#include
d beberapa kali saat mengkompilasi satu.cpp
filesumber
Dengan kompiler Microsoft [1], variabel statis yang tidak
int
seperti juga dapat didefinisikan dalam file header, tetapi di luar deklarasi kelas, menggunakan spesifik Microsoft__declspec(selectany)
.Perhatikan bahwa saya tidak mengatakan ini bagus, saya hanya mengatakan itu bisa dilakukan.
[1] Saat ini, lebih banyak kompiler daripada dukungan MSC
__declspec(selectany)
- setidaknya gcc dan dentang. Mungkin bahkan lebih.sumber
Adalah sintaks yang benar untuk menginisialisasi variabel, tetapi harus masuk dalam file sumber (.cpp) daripada di header.
Karena itu adalah variabel statis, kompiler hanya perlu membuat satu salinannya. Anda harus memiliki baris "int foo: i" di suatu tempat dalam kode Anda untuk memberi tahu kompiler di mana harus meletakkannya jika tidak, Anda mendapatkan kesalahan tautan. Jika itu ada di header, Anda akan mendapatkan salinan di setiap file yang menyertakan header, jadi dapatkan kesalahan simbol berlipat ganda dari linker.
sumber
Saya tidak punya cukup perwakilan di sini untuk menambahkan ini sebagai komentar, tetapi IMO itu gaya yang baik untuk menulis header Anda dengan #include penjaga , yang seperti dicatat oleh Paranaix beberapa jam yang lalu akan mencegah kesalahan definisi ganda. Kecuali Anda sudah menggunakan file CPP yang terpisah, tidak perlu menggunakan hanya untuk menginisialisasi anggota non-integral statis.
Saya melihat tidak perlu menggunakan file CPP terpisah untuk ini. Tentu, Anda bisa, tetapi tidak ada alasan teknis mengapa Anda harus melakukannya.
sumber
#endif // FOO_H
#pragma once
Jika Anda ingin menginisialisasi beberapa tipe majemuk (fe string) Anda dapat melakukan sesuatu seperti itu:
Karena
ListInitializationGuard
merupakan variabel statis di dalamSomeClass::getList()
metode itu akan dibangun hanya sekali, yang berarti bahwa konstruktor dipanggil sekali. Ini akaninitialize _list
variabel ke nilai yang Anda butuhkan. Setiap panggilan selanjutnyagetList
hanya akan mengembalikan objek yang sudah diinisialisasi_list
.Tentu saja Anda harus mengakses
_list
objek selalu dengan memanggilgetList()
metode.sumber
C ++ 11 pola konstruktor statis yang berfungsi untuk banyak objek
Satu idiom diusulkan di: https://stackoverflow.com/a/27088552/895245 tetapi inilah versi yang lebih bersih yang tidak perlu membuat metode baru per anggota.
main.cpp
GitHub hulu .
Kompilasi dan jalankan:
Lihat juga: konstruktor statis di C ++? Saya perlu menginisialisasi objek statis pribadi
Diuji pada Ubuntu 19.04.
C ++ 17 variabel sebaris
Disebutkan di: https://stackoverflow.com/a/45062055/895245 tapi di sini ada contoh runnable multi-guna membuatnya lebih jelas: Bagaimana cara kerja variabel inline?
sumber
Anda juga bisa memasukkan tugas dalam file header jika Anda menggunakan penjaga header. Saya telah menggunakan teknik ini untuk pustaka C ++ yang telah saya buat. Cara lain untuk mencapai hasil yang sama adalah dengan menggunakan metode statis. Sebagai contoh...
Kode di atas memiliki "bonus" karena tidak memerlukan file CPP / sumber. Sekali lagi, metode yang saya gunakan untuk pustaka C ++ saya.
sumber
Saya mengikuti ide dari Karl. Saya menyukainya dan sekarang saya menggunakannya juga. Saya telah mengubah sedikit notasi dan menambahkan beberapa fungsi
output ini
sumber
Juga bekerja di file privateStatic.cpp:
sumber
Bagaimana dengan
set_default()
metode?Kami hanya perlu menggunakan
set_default(int x)
metode dan kamistatic
variabel akan diinisialisasi.Ini tidak akan bertentangan dengan sisa komentar, sebenarnya mengikuti prinsip yang sama menginisialisasi variabel dalam lingkup global, tetapi dengan menggunakan metode ini kami membuatnya eksplisit (dan mudah dipahami) bukan memiliki definisi dari variabel yang tergantung di sana.
sumber
Masalah tautan yang Anda temui mungkin disebabkan oleh:
Ini adalah masalah umum bagi mereka yang memulai dengan C ++. Anggota kelas statis harus diinisialisasi dalam unit terjemahan tunggal yaitu dalam file sumber tunggal.
Sayangnya, anggota kelas statis harus diinisialisasi di luar tubuh kelas. Ini menyulitkan penulisan kode hanya header, dan oleh karena itu, saya menggunakan pendekatan yang sangat berbeda. Anda dapat memberikan objek statis Anda melalui fungsi kelas statis atau non-statis misalnya:
sumber
Salah satu cara "jadul" untuk mendefinisikan konstanta adalah dengan menggantinya dengan
enum
:Cara ini tidak memerlukan memberikan definisi, dan menghindari membuat konstan lvalue , yang dapat menghemat beberapa sakit kepala, misalnya ketika Anda secara tidak sengaja ODR digunakan itu.
sumber
Saya hanya ingin menyebutkan sesuatu yang sedikit aneh bagi saya ketika saya pertama kali menemukan ini.
Saya perlu menginisialisasi anggota data statis pribadi di kelas templat.
di .h atau .hpp, terlihat seperti ini untuk menginisialisasi anggota data statis dari kelas templat:
sumber
Apakah ini sesuai dengan tujuan Anda?
sumber