C++: mengakses var anggota const melalui kelas atau instance?

Di C++, apakah ada alasan untuk tidak mengakses variabel anggota statis melalui instance kelas? Saya tahu Java tidak menyukai hal ini dan bertanya-tanya apakah itu penting di C++. Contoh:

class Foo {
  static const int ZERO = 0;
  static const int ONE = 1;
  ...
};


void bar(const Foo& inst) {
   // is this ok?
   int val1 = inst.ZERO;
   // or should I prefer:
   int val2 = Foo::ZERO
   ...
};

Saya punya bonus pertanyaan kedua. Jika saya mendeklarasikan double statis, saya harus mendefinisikannya di suatu tempat dan definisi itu harus mengulangi tipenya. Mengapa tipenya harus diulang? Misalnya:

In a header:
  class Foo {
    static const double d;
  };
In a source file:
  const double Foo::d = 42;

Mengapa saya harus mengulangi bagian "const double" di file cpp saya?


person criddell    schedule 06.08.2009    source sumber
comment
Bukan duplikat yang sama persis, tapi menurut saya jawaban yang sama mungkin berlaku: stackoverflow.com/questions/840522/   -  person Fred Larson    schedule 07.08.2009
comment
Ya. Baca jawaban Adam Rosenthal untuk alasan sangat bagus mengapa Anda sebaiknya memilih kelas sebagai awalan daripada sebuah instance.   -  person quark    schedule 07.08.2009


Jawaban (6)


Untuk pertanyaan pertama, selain soal gaya (sudah jelas bahwa ini adalah variabel kelas dan tidak memiliki objek terkait), Fred Larsen, dalam komentar atas pertanyaan tersebut, mengacu pada pertanyaan sebelumnya. Baca Jawaban Adam Rosenthal untuk sangat alasan bagus mengapa Anda ingin berhati-hati dengan ini. (Saya akan memilih Fred jika dia mempostingnya sebagai jawaban, tetapi saya tidak dapat menghargai di mana seharusnya jawabannya. Saya memilih Adam.)

Mengenai pertanyaan kedua Anda:

Mengapa saya harus mengulangi bagian "const double" di file cpp saya?

Anda harus mengulangi tipe ini terutama sebagai detail implementasi: begitulah cara kompiler C++ mem-parsing sebuah deklarasi. Ini juga tidak ideal untuk variabel lokal, dan C++1x (sebelumnya C++0x) menggunakan kata kunci auto untuk menghindari pengulangan untuk variabel fungsi reguler.

Jadi ini:

vector<string> v;
vector<string>::iterator it = v.begin();

bisa menjadi ini:

vector<string> v;
auto it = v.begin();

Tidak ada alasan yang jelas mengapa ini tidak bisa bekerja dengan statis juga, jadi dalam kasus Anda:

const double Foo::d = 42;

bisa menjadi seperti ini.

static Foo::d = 42;

Kuncinya adalah memiliki beberapa cara untuk mengidentifikasi hal ini sebagai sebuah deklarasi.

Catatan Saya mengatakan tidak ada alasan yang jelas: Tata bahasa C++ adalah legenda hidup: sangat sulit untuk mencakup semua kasus tepinya. Menurut saya, hal di atas tidak berpikir ambigu, tetapi mungkin saja ambigu. Jika tidak, mereka dapat menambahkannya ke bahasa tersebut. Beritahu mereka tentang hal itu ... untuk C++2x :/.

person quark    schedule 06.08.2009

Saya lebih memilih Foo::ZERO daripada inst.ZERO karena lebih jelas menjelaskan apa yang sedang terjadi. Namun, dalam metode kelas Foo, saya hanya akan menggunakan ZERO.

Sedangkan untuk soal bonus, const hanya merupakan bagian dari tipe lengkap.

person Reunanen    schedule 06.08.2009
comment
Saya memahami bahwa const adalah bagian dari tipe. Saya bertanya-tanya mengapa saya harus mengulangi tipe itu sama sekali. Saya hanya ingin mengatakan: Foo::d = 42; Hanya ada satu Foo::d yang dideklarasikan di file header. Apakah ini menimbulkan kemungkinan ambiguitas yang tidak saya lihat di sini? Mungkinkah ada fungsi anggota bernama d? Saya tahu ada alasan bagus untuk mengulangi tipe tersebut, saya hanya tidak tahu apa itu. - person criddell; 07.08.2009
comment
Mungkin itu hanya aturan bahasanya? - person Juan; 07.08.2009
comment
Saya mencoba menjelaskan ini di komentar tetapi kehabisan ruangan (menghela nafas). Saya menjawabnya di bawah. - person quark; 07.08.2009

Mengingat Anda mendeklarasikannya sebagai statis dan menjadikannya konstanta kelas, saya akan menggunakan Foo::Zero untuk mengkomunikasikan maksudnya kepada pembaca kode Anda yang biasa dan tidak terlalu biasa.

Saya juga akan mengganti semua nama konstanta dengan huruf besar, yaitu mengubah Foo::ZERO menjadi Foo::Zero. Konvensi normal untuk makro praprosesor adalah menamainya dalam huruf besar semua dan menggunakan skema penamaan serupa untuk konstanta C++ Anda akan menimbulkan masalah karena praprosesor mungkin akan merusak konstanta C++ Anda dan Anda akan mendapatkan pesan kesalahan yang sangat menarik.

person Timo Geusch    schedule 06.08.2009
comment
Wow- poin bagus dalam konvensi penamaan. Saya sebenarnya telah mengalami hal ini lebih dari satu kali (tolong, semuanya-- hentikan #mendefinisikan PI!!!) - person criddell; 07.08.2009

Saya akan menggunakan Foo::ZERO, tapi itu hanya saya. Terutama jika Anda berasal dari Foo, yang akan membingungkan.

Untuk pertanyaan kedua Anda, Anda perlu membuat memori untuk nilai ganda, dan itu terjadi di unit implementasi.

Saya pikir satu-satunya tipe yang Anda tidak perlu membuat memori adalah tipe integral const. Anda kemudian dapat memasukkan nilainya ke dalam file header. Namun karena tidak memiliki alamat, Anda tidak akan bisa meneruskannya dengan referensi ke suatu fungsi, kecuali Anda memasukkan definisi ke dalam file .cpp. (Sepertinya ini cara kerjanya dengan gcc).

person Juan    schedule 06.08.2009

Tidak masalah bentuk apa yang Anda gunakan dalam contoh Anda. Keduanya memiliki arti yang sama. Saya lebih suka menggunakan cara kelas secara umum karena Anda mungkin tidak selalu memiliki instance yang berguna untuk menggunakan operator titik.

Sangat menyenangkan memiliki kedua opsi jika Anda mempertimbangkan seseorang untuk menulis fungsi templat. Mereka mungkin telah mengkodekan fungsinya dengan operator titik. Kelas Anda dengan anggota kelas statis masih dapat digunakan untuk membuat instance templat karena sintaksis tersebut didukung.

Kalau pertanyaan bonusnya, bahasanya memang begitu. Anda selalu harus mendeklarasikan tipe lengkap. Anda mungkin harus menanyakannya dalam pertanyaan terpisah.

person Brian Neal    schedule 06.08.2009

secara pribadi saya akan menggunakan enum anonim. Hasil akhirnya sama persis :)

Adapun pertanyaan Anda. Saya pasti lebih suka Foo::Zero karena jelas dari melihat apa yang Anda akses. inst.Zero mengharuskan Anda untuk mengetahui jenis inst sebelumnya.

Anda harus mengulangi tipe data karena itulah cara kerja C++. Dengan cara yang sama jika Anda menulis yang berikut ini di file header.

extern int foo;

Anda masih perlu menyebutkannya

int foo

dalam file CPP. Seperti yang disebutkan pukku, Anda mendeklarasikan variabel bertipe "const int". Jadi "const int" harus diulangi dalam definisi variabel.

person Goz    schedule 06.08.2009
comment
enum anonim memaksa ukuran penyimpanan tertentu (int). Jika Anda ingin konstanta bertipe berbeda, maka Anda tidak dapat menggunakan enum anonim. - person Chris Cleeland; 07.08.2009