Mengapa saya tidak dapat menginisialisasi non-const static
member atau static
array di kelas?
class A
{
static const int a = 3;
static int b = 3;
static const int c[2] = { 1, 2 };
static int d[2] = { 1, 2 };
};
int main()
{
A a;
return 0;
}
kompilator mengeluarkan kesalahan berikut:
g++ main.cpp
main.cpp:4:17: error: ISO C++ forbids in-class initialization of non-const static member ‘b’
main.cpp:5:26: error: a brace-enclosed initializer is not allowed here before ‘{’ token
main.cpp:5:33: error: invalid in-class initialization of static data member of non-integral type ‘const int [2]’
main.cpp:6:20: error: a brace-enclosed initializer is not allowed here before ‘{’ token
main.cpp:6:27: error: invalid in-class initialization of static data member of non-integral type ‘int [2]’
Saya punya dua pertanyaan:
- Mengapa saya tidak dapat menginisialisasi
static
anggota data di kelas? - Mengapa saya tidak bisa menginisialisasi
static
array di kelas, bahkanconst
array?
Jawaban:
Mengapa saya tidak dapat menginisialisasi
static
anggota data di kelas?Standar C ++ hanya mengizinkan jenis integral konstanta statis atau enumerasi untuk diinisialisasi di dalam kelas. Inilah alasannya
a
diizinkan untuk diinisialisasi sementara yang lain tidak.Referensi:
C ++ 03 9.4.2 Anggota data statis
§4
Apa tipe integral?
C ++ 03 3.9.1 Tipe dasar
§7
Catatan kaki:
Solusi:
Anda bisa menggunakan trik enum untuk menginisialisasi array di dalam definisi kelas Anda.
Mengapa Standar tidak mengizinkan ini?
Bjarne menjelaskan hal ini dengan tepat di sini :
Mengapa hanya
static const
tipe integral & enum yang diperbolehkan In-class Initialization?Jawabannya tersembunyi dalam kutipan Bjarne. Bacalah dengan seksama,
"C ++ mengharuskan setiap objek memiliki definisi yang unik. Aturan itu akan rusak jika C ++ mengizinkan definisi entitas dalam kelas yang perlu disimpan dalam memori sebagai objek."
Perhatikan bahwa hanya
static const
bilangan bulat yang dapat diperlakukan sebagai konstanta waktu kompilasi. Kompilator mengetahui bahwa nilai integer tidak akan berubah setiap saat dan karenanya ia dapat menerapkan sihirnya sendiri dan menerapkan pengoptimalan, kompilator hanya menyebariskan anggota kelas seperti itu, yaitu mereka tidak disimpan dalam memori lagi, Karena kebutuhan untuk disimpan dalam memori telah dihapus , itu memberikan variabel seperti pengecualian untuk aturan yang disebutkan oleh Bjarne.Perlu dicatat di sini bahwa meskipun
static const
nilai integral dapat memiliki In-Class Initialization, mengambil alamat variabel tersebut tidak diperbolehkan. Seseorang dapat mengambil alamat dari anggota statis jika (dan hanya jika) memiliki definisi di luar kelas. Ini selanjutnya memvalidasi alasan di atas.enum diperbolehkan ini karena nilai dari tipe enumerasi dapat digunakan di mana int diharapkan. lihat kutipan di atas
Bagaimana ini berubah di C ++ 11?
C ++ 11 melonggarkan pembatasan sampai batas tertentu.
C ++ 11 9.4.2 Anggota data statis
§3
Selain itu, C ++ 11 akan mengizinkan (§12.6.2.8) anggota data non-statis diinisialisasi di tempat ia dideklarasikan (di kelasnya). Ini berarti semantik pengguna yang lebih mudah.
Perhatikan bahwa fitur-fitur ini belum diimplementasikan di gcc 4.7 terbaru, Jadi Anda mungkin masih mendapatkan kesalahan kompilasi.
sumber
&member
kembali?static const char*
anggota?Ini tampaknya merupakan peninggalan dari masa lalu penaut sederhana. Anda dapat menggunakan variabel statis dalam metode statis sebagai solusi:
dan
dan
membangun:
Lari:
Fakta bahwa ini berfungsi (secara konsisten, meskipun definisi kelas disertakan dalam unit kompilasi yang berbeda), menunjukkan bahwa linker saat ini (gcc 4.9.2) sebenarnya cukup pintar.
Lucu: Sidik jari
0123
di lengan dan3210
di x86.sumber
Saya pikir itu untuk mencegah Anda mencampurkan deklarasi dan definisi. (Pikirkan tentang masalah yang dapat terjadi jika Anda menyertakan file di banyak tempat.)
sumber
Itu karena hanya ada satu definisi
A::a
yang digunakan semua unit terjemahan.Jika Anda tampil
static int a = 3;
di kelas dalam tajuk yang termasuk dalam semua unit terjemahan maka Anda akan mendapatkan banyak definisi. Oleh karena itu, definisi non-out-of-line dari statis secara paksa membuat kesalahan kompiler.Menggunakan
static inline
ataustatic const
memperbaikinya.static inline
hanya mengkonkretkan simbol jika digunakan dalam unit terjemahan dan memastikan penaut hanya memilih dan meninggalkan satu salinan jika ditentukan di beberapa unit terjemahan karena berada dalam grup comdat.const
pada ruang lingkup file membuat kompilator tidak pernah memancarkan simbol karena itu selalu diganti segera dalam kode kecualiextern
digunakan, yang tidak diizinkan di kelas.Satu hal yang perlu diperhatikan adalah
static inline int b;
diperlakukan sebagai definisi sedangkanstatic const int b
ataustatic const A b;
masih diperlakukan sebagai deklarasi dan harus didefinisikan out-of-line jika Anda tidak mendefinisikannya di dalam kelas. Menariknyastatic constexpr A b;
diperlakukan sebagai definisi, sedangkanstatic constexpr int b;
kesalahan dan harus memiliki penginisialisasi (ini karena mereka sekarang menjadi definisi dan seperti definisi const / constexpr pada ruang lingkup file, mereka memerlukan penginisialisasi yang int tidak memiliki tetapi tipe kelas tidak karena memiliki implisit= A()
ketika itu adalah definisi - clang memungkinkan ini tetapi gcc mengharuskan Anda untuk menginisialisasi secara eksplisit atau ini adalah kesalahan. Ini bukan masalah dengan sebaris).static const A b = A();
tidak diperbolehkan dan harusconstexpr
atauinline
untuk mengizinkan penginisialisasi objek statis dengan tipe kelas yaitu membuat anggota statis dari tipe kelas lebih dari sekedar deklarasi. Jadi ya dalam situasi tertentuA a;
tidak sama dengan inisialisasi eksplisitA a = A();
(yang pertama bisa berupa deklarasi tetapi jika hanya deklarasi yang diizinkan untuk jenis itu maka yang terakhir adalah kesalahan. Yang terakhir hanya dapat digunakan pada definisi.constexpr
Menjadikannya definisi ). Jika Anda menggunakanconstexpr
dan menetapkan konstruktor default, maka konstruktor tersebut harusconstexpr
Anggota statis adalah deklarasi cakupan file langsung
extern int A::a;
(yang hanya dapat dibuat di kelas dan definisi di luar baris harus merujuk ke anggota statis dalam kelas dan harus berupa definisi dan tidak boleh berisi eksternal) sedangkan anggota non-statis adalah bagian dari definisi tipe lengkap kelas dan memiliki aturan yang sama dengan deklarasi cakupan file tanpaextern
. Mereka adalah definisi yang implisit. Begituint i[]; int i[5];
juga redefinisi dimanastatic int i[]; int A::i[5];
tidak tetapi tidak seperti 2 externs, kompilator masih akan mendeteksi anggota duplikat jika Anda melakukannyastatic int i[]; static int i[5];
di kelas.sumber
variabel statis dikhususkan untuk kelas. Konstruktor menginisialisasi atribut TERUTAMA untuk sebuah instance.
sumber