Saya ingin memiliki konstanta statis pribadi untuk kelas (dalam hal ini bentuk-pabrik).
Saya ingin memiliki sesuatu seperti itu.
class A {
private:
static const string RECTANGLE = "rectangle";
}
Sayangnya saya mendapatkan semua jenis kesalahan dari kompiler C ++ (g ++), seperti:
ISO C ++ melarang inisialisasi anggota 'RECTANGLE'
inisialisasi in-class yang tidak valid dari anggota data statis tipe non-integral 'std :: string'
kesalahan: membuat 'RECTANGLE' statis
Ini memberitahu saya bahwa desain anggota semacam ini tidak sesuai dengan standar. Bagaimana Anda memiliki konstanta literal pribadi (atau mungkin publik) tanpa harus menggunakan arahan #define (saya ingin menghindari keburukan data global!)
Bantuan apa pun dihargai.
Jawaban:
Anda harus mendefinisikan anggota statis Anda di luar definisi kelas dan menyediakan inisialisasi di sana.
Pertama
lalu
Sintaks yang awalnya Anda coba gunakan (initializer di dalam definisi kelas) hanya diperbolehkan dengan tipe integral dan enum.
Mulai dari C ++ 17 Anda memiliki opsi lain, yang sangat mirip dengan deklarasi asli Anda: variabel inline
Tidak diperlukan definisi tambahan.
Atau alih-alih
const
Anda dapat mendeklarasikannyaconstexpr
dalam varian ini. Eksplisitinline
tidak lagi diperlukan, karenaconstexpr
tersiratinline
.sumber
char const*
memiliki kebaikan bahwa itu diinisialisasi sebelum semua inisialisasi dinamis dilakukan. Jadi dalam konstruktor objek apa pun, Anda dapat mengandalkanRECTANGLE
telah diinisialisasi sebelumnya.Di C ++ 11 Anda dapat melakukannya sekarang:
sumber
constexpr
menyiratkanconst
untuk var, bukan untuk mengetikkan poin. Yaitustatic constexpr const char* const
sama denganstatic constexpr const char*
, tetapi tidak sama denganstatic constexpr char*
.Di dalam definisi kelas Anda hanya dapat mendeklarasikan anggota statis. Mereka harus didefinisikan di luar kelas. Untuk konstanta integral kompilasi waktu, standar membuat pengecualian bahwa Anda dapat "menginisialisasi" anggota. Itu masih bukan definisi. Mengambil alamat tidak akan berfungsi tanpa definisi, misalnya.
Saya ingin menyebutkan bahwa saya tidak melihat manfaat dari menggunakan std :: string over const char [] untuk konstanta . std :: string bagus dan semua tetapi membutuhkan inisialisasi dinamis. Jadi, jika Anda menulis sesuatu seperti
pada lingkup namespace, konstruktor foo akan dijalankan tepat sebelum eksekusi mulai utama dan konstruktor ini akan membuat salinan konstanta "halo" di memori tumpukan. Kecuali Anda benar-benar membutuhkan RECTANGLE untuk menjadi std :: string yang Anda bisa tulis
Sana! Tidak ada alokasi tumpukan, tidak ada penyalinan, tidak ada inisialisasi dinamis.
Cheers, s.
sumber
Ini hanya informasi tambahan, tetapi jika Anda benar-benar menginginkan string dalam file header, coba sesuatu seperti:
Meskipun aku ragu itu direkomendasikan.
sumber
Di C ++ 17 Anda dapat menggunakan variabel sebaris :
Perhatikan bahwa ini berbeda dari jawaban yang buruk.7 : Yang ini mendefinisikan
std::string
objek aktual , bukan aconst char*
sumber
inline
akan membuat banyak duplikat?Ini batasannya. Karenanya, dalam hal ini Anda perlu mendefinisikan variabel di luar kelas. lihat jawaban dari @AndreyT
sumber
Variabel statis kelas dapat dideklarasikan di header tetapi harus didefinisikan dalam file .cpp. Ini karena hanya ada satu contoh variabel statis dan kompilator tidak dapat memutuskan di mana file objek yang dihasilkan untuk meletakkannya sehingga Anda harus membuat keputusan.
Untuk menjaga definisi nilai statis dengan deklarasi di C ++ 11 struktur statis bersarang dapat digunakan. Dalam hal ini anggota statis adalah struktur dan harus didefinisikan dalam file .cpp, tetapi nilainya ada di header.
Alih-alih menginisialisasi anggota individu seluruh struktur statis diinisialisasi dalam .cpp:
Nilai diakses dengan
atau - karena anggotanya pribadi dan dimaksudkan untuk digunakan hanya dari A - with
Perhatikan bahwa solusi ini masih menderita dari masalah urutan inisialisasi variabel statis. Ketika nilai statis digunakan untuk menginisialisasi variabel statis lain, yang pertama mungkin belum diinisialisasi.
Dalam hal ini header variabel statis akan berisi {""} atau {".h", ".hpp"}, tergantung pada urutan inisialisasi yang dibuat oleh penghubung.
Seperti disebutkan oleh @ abyss.7 Anda juga dapat menggunakan
constexpr
jika nilai variabel dapat dihitung pada waktu kompilasi. Tetapi jika Anda mendeklarasikan string Andastatic constexpr const char*
dan program Anda menggunakanstd::string
sebaliknya, akan ada overhead karenastd::string
objek baru akan dibuat setiap kali Anda menggunakan konstanta seperti itu:sumber
Standar saat ini hanya memungkinkan inisialisasi tersebut untuk jenis integral konstan statis. Jadi, Anda perlu melakukan seperti yang dijelaskan AndreyT. Namun, itu akan tersedia dalam standar berikutnya melalui sintaks inisialisasi anggota baru .
sumber
mungkin lakukan saja:
atau
sumber
constexpr
tetapi Anda tidak dapat membuat fungsi statisconst
.static const std::string RECTANGLE() const { static const std::string value("rectangle"); return value; }
Anda bisa menggunakan
const char*
solusi yang disebutkan di atas, tetapi jika Anda membutuhkan string setiap saat, Anda akan memiliki banyak overhead.Di sisi lain, string statis membutuhkan inisialisasi dinamis, jadi jika Anda ingin menggunakan nilainya selama inisialisasi variabel global / statis lain, Anda mungkin mengalami masalah urutan inisialisasi. Untuk menghindari itu, hal termurah adalah mengakses objek string statis melalui pengambil, yang memeriksa apakah objek Anda diinisialisasi atau tidak.
Ingatlah untuk hanya menggunakan
A::getS()
. Karena setiap threading hanya dapat dimulai denganmain()
, danA_s_initialized
diinisialisasi sebelumnyamain()
, Anda tidak perlu kunci bahkan dalam lingkungan multithreadedA_s_initialized
adalah 0 secara default (sebelum inisialisasi dinamis), jadi jika Anda menggunakangetS()
sebelum s diinisialisasi, Anda memanggil fungsi init dengan aman.Btw, dalam jawaban di atas: " static const std :: string RECTANGLE () const ", fungsi statis tidak bisa
const
karena mereka tidak dapat mengubah keadaan jika objek tetap (tidak ada pointer ini).sumber
Maju cepat ke 2018 dan C ++ 17.
static_assert 'works' hanya pada waktu kompilasi
};
Di atas adalah standar warga negara C ++ yang tepat dan sah. Itu bisa dengan mudah terlibat dalam setiap dan semua std :: algoritma, wadah, utilitas dan semacamnya. Sebagai contoh:
Nikmati C ++ standar
sumber
std::string_view
untuk konstanta hanya jika Anda menggunakanstring_view
parameter di semua fungsi Anda. Jika salah satu fungsi Anda menggunakanconst std::string&
parameter, salinan string akan dibuat ketika Anda melewatistring_view
konstanta melalui parameter itu. Jika konstanta Anda bertipestd::string
salinan tidak akan dibuat baik untukconst std::string&
parameter maupun untukstd::string_view
parameter.inline
variabel tiba di C ++ 17 dengan semantik ODR mereka. Tapi string_view adalah C ++ 17 juga, jadi hanyaconstexpr auto some_str = "compile time"sv;
melakukan pekerjaan (dan sebenarnya, itu bukan variabel, ituconstexpr
, jadiinline
implisit; jika Anda memiliki variabel - yaitu tidakconstexpr
- makainline auto some_str = "compile time"sv;
akan melakukannya, meskipun tentu saja namespace-scope variabel, yang pada dasarnya adalah variabel global, jarang merupakan ide yang bagus).