Mengapa fungsi anggota const mengubah anggota data statis?

86

Dalam C++program berikut , memodifikasi anggota data statis dari suatu constfungsi berfungsi dengan baik:

class A 
{
  public:   
    static int a; // static data member

    void set() const
    {
        a = 10;
    }
};

Tetapi memodifikasi anggota data non-statis dari suatu constfungsi tidak berfungsi:

class A 
{
  public:   
    int a; // non-static data member

    void set() const
    {
        a = 10;
    }
};

Mengapa constfungsi anggota mengubah anggota staticdata?

msc
sumber
Akan sangat membantu jika Anda dapat memberi tahu kami platform dan kompiler mana yang Anda gunakan? Jadi kami dapat menentukan apakah perilakunya adalah bug yang terkait dengan penyiapan spesifik Anda atau apakah perilakunya memang benar dan hanya perlu dijelaskan.
Alex Zywicki
@AlexZywicki G ++ pada platform Linux.
msc
8
Tidak dibutuhkan. Ini disengaja dan semua kompiler C ++ harus mendukungnya. Tapi mengapa pertanyaan bagus seperti ini tidak mendapat suara positif lagi?
Batsyeba
18
Ini penipuan, tetapi lebih baik ditulis daripada yang lain berkat MCVE yang lebih baik, jadi saya menggunakan ini sebagai target.
Baum mit Augen
5
Motivasi di sini constberarti fungsi anggota suatu objek tidak dapat memodifikasi objek yang satu itu . Itu dapat memodifikasi objek lain dari kelas yang sama, atau staticdata, yang terkait dengan kelas, bukan contoh tertentu darinya. (Atau mutableanggota data, yang dibuat untuk menjadi pengecualian dari aturan ini.)
Davislor

Jawaban:

100

Itu aturannya, itu saja. Dan untuk alasan yang bagus.

The constkualifikasi pada fungsi anggota berarti bahwa Anda tidak dapat memodifikasi non mutablenon staticvariabel anggota kelas.

Dengan cara menawarkan beberapa rasionalisasi, thispenunjuk dalam constfungsi anggota yang memenuhi syarat adalah sebuah consttipe, dan thissecara inheren terkait dengan sebuah instance kelas. staticanggota tidak terkait dengan instance kelas. Anda tidak memerlukan contoh untuk mengubah staticanggota: Anda dapat melakukannya, dalam kasus Anda, dengan menulis A::a = 10;.

Jadi, dalam kasus pertama Anda, anggap a = 10;sebagai singkatan untuk A::a = 10;dan dalam kasus kedua, anggap itu sebagai singkatan dari this->a = 10;, yang tidak dapat disusun karena jenisnya thisadalah const A*.

Batsyeba
sumber
1
Hanya sedikit kesalahan di sini: Karena Anda tidak dapat menetapkan kembali thispointer, itu akan menjadi tipe const A* const di constkasus 's.
Taylor Hansen
2
@TaylorHansen thisadalah nilai pr dari tipe penunjuk. Nilai dari jenis non-kelas tidak pernah memenuhi syarat cv.
21

Menurut Standar C ++ (9.2.3.2 Anggota data statis)

1 Anggota data statis bukan bagian dari subobjek kelas ...

Dan (9.2.2.1 Penunjuk ini)

1 Dalam tubuh fungsi anggota non-statis (9.2.1), kata kunci this adalah ekspresi prvalue yang nilainya adalah alamat objek yang dipanggil oleh fungsi tersebut. Jenis ini dalam fungsi anggota kelas X adalah X *. Jika fungsi anggota dideklarasikan const, jenisnya adalah const X * , ...

Dan akhirnya (9.2.2 Fungsi anggota non-statis)

3 ... jika pencarian nama (3.4) menyelesaikan nama dalam ekspresi-id menjadi anggota non-tipe non-statis dari beberapa kelas C, dan jika ekspresi-id berpotensi dievaluasi atau C adalah X atau kelas dasar dari X, ekspresi-id diubah menjadi ekspresi akses anggota kelas (5.2.5) menggunakan (* this) (9.2.2.1) sebagai ekspresi-postfix di sebelah kiri. operator.

Demikianlah dalam definisi kelas ini

class A 
{
  public:   
    static int a; 

    void set() const
    {
        a = 10;
    }
};

anggota data statis abukan merupakan subobjek dari sebuah objek dari tipe kelas dan penunjukthis tidak digunakan untuk mengakses anggota data statis. Jadi setiap fungsi anggota, konstanta non-statis atau non-konstan, atau fungsi anggota statis dapat mengubah anggota data karena itu bukan konstanta.

Dalam definisi kelas ini

class A 
{
  public:   
    int a; 

    void set() const
    {
        a = 10;
    }
};

anggota data non-statis aadalah subobjek dari sebuah objek dari tipe kelas. Untuk mengaksesnya dalam fungsi anggota digunakan baik sintaks akses anggota dari sintaks ini tersirat. Anda tidak boleh menggunakan penunjuk konstan thisuntuk mengubah anggota data. Dan pointer ini memang memiliki tipe const A *di dalam fungsinya setkarena fungsinya dideklarasikan dengan qualifier const. Jika fungsi tidak memiliki kualifikasi dalam hal ini anggota data dapat diubah.

Vlad dari Moskow
sumber
13

Masalahnya, jika fungsi anggota kelas Aadalah const, maka jenisnya thisadalah const X*, dan dengan demikian mencegah anggota data non-statis diubah (cf, misalnya, standar C ++ ):

9.3.2 Penunjuk ini [class.this]

Dalam tubuh fungsi anggota non-statis (9.3), kata kunci this adalah ekspresi prvalue yang nilainya adalah alamat objek yang dipanggil oleh fungsi tersebut. Jenis ini dalam fungsi anggota kelas X adalah X *. Jika fungsi anggota dideklarasikan const, jenisnya adalah const X *, ...

Jika amerupakan anggota data non-statis, maka a=10sama dengan this->a = 10, yang tidak diperbolehkan jika tipe thisadalah const A*dan abelum dideklarasikan sebagai mutable. Jadi, karena void set() constmembuat tipe thismakhluk const A*, akses ini tidak diperbolehkan.

aSebaliknya, jika merupakan anggota data statis, maka a=10tidak melibatkan thissama sekali; dan selama static int abelum dinyatakan sebagai const, pernyataan a=10diperbolehkan.

Stephan Lechner
sumber
1

The constkualifikasi pada fungsi anggota berarti bahwa Anda tidak dapat memodifikasi non-mutable, non-static data anggota kelas .

Li Kui
sumber