Arti 'const' terakhir dalam deklarasi fungsi suatu kelas?

727

Apa arti dari constdeklarasi seperti ini? Yang constmembingungkan saya.

class foobar
{
  public:
     operator int () const;
     const char* foo() const;
};
Rakete1111
sumber

Jawaban:

951

Ketika Anda menambahkan constkata kunci ke suatu metode, thispointer pada dasarnya akan menjadi pointer ke constobjek, dan karena itu Anda tidak dapat mengubah data anggota. (Kecuali Anda menggunakan mutable, lebih lanjut tentang itu nanti).

Kata constkunci adalah bagian dari tanda tangan fungsi yang berarti bahwa Anda dapat menerapkan dua metode serupa, satu yang disebut ketika objek const, dan satu yang tidak.

#include <iostream>

class MyClass
{
private:
    int counter;
public:
    void Foo()
    { 
        std::cout << "Foo" << std::endl;    
    }

    void Foo() const
    {
        std::cout << "Foo const" << std::endl;
    }

};

int main()
{
    MyClass cc;
    const MyClass& ccc = cc;
    cc.Foo();
    ccc.Foo();
}

Ini akan menampilkan

Foo
Foo const

Dalam metode non-const, Anda dapat mengubah anggota instance, yang tidak dapat Anda lakukan dalam constversi. Jika Anda mengubah deklarasi metode dalam contoh di atas ke kode di bawah ini Anda akan mendapatkan beberapa kesalahan.

    void Foo()
    {
        counter++; //this works
        std::cout << "Foo" << std::endl;    
    }

    void Foo() const
    {
        counter++; //this will not compile
        std::cout << "Foo const" << std::endl;
    }

Ini tidak sepenuhnya benar, karena Anda dapat menandai anggota sebagai mutabledan constmetode kemudian dapat mengubahnya. Ini sebagian besar digunakan untuk penghitung internal dan barang-barang. Solusi untuk itu adalah kode di bawah ini.

#include <iostream>

class MyClass
{
private:
    mutable int counter;
public:

    MyClass() : counter(0) {}

    void Foo()
    {
        counter++;
        std::cout << "Foo" << std::endl;    
    }

    void Foo() const
    {
        counter++;    // This works because counter is `mutable`
        std::cout << "Foo const" << std::endl;
    }

    int GetInvocations() const
    {
        return counter;
    }
};

int main(void)
{
    MyClass cc;
    const MyClass& ccc = cc;
    cc.Foo();
    ccc.Foo();
    std::cout << "Foo has been invoked " << ccc.GetInvocations() << " times" << std::endl;
}

yang akan menghasilkan

Foo
Foo const
Foo has been invoked 2 times
Mats Fredriksson
sumber
187

Konst tersebut berarti bahwa metode ini berjanji untuk tidak mengubah anggota kelas. Anda dapat mengeksekusi anggota objek yang ditandai, bahkan jika objek itu sendiri ditandai const:

const foobar fb;
fb.foo();

akan legal.

Lihat Berapa banyak dan mana yang menggunakan "const" di C ++? untuk informasi lebih lanjut.

Blair Conrad
sumber
47

The constberarti kualifikasi bahwa metode dapat disebut pada setiap nilai foobar. Perbedaannya muncul ketika Anda mempertimbangkan untuk memanggil metode non-const pada objek const. Pertimbangkan apakah foobartipe Anda memiliki deklarasi metode tambahan berikut:

class foobar {
  ...
  const char* bar();
}

Metode bar()ini non-const dan hanya dapat diakses dari nilai non-const.

void func1(const foobar& fb1, foobar& fb2) {
  const char* v1 = fb1.bar();  // won't compile
  const char* v2 = fb2.bar();  // works
}

Gagasan di belakang constadalah untuk menandai metode yang tidak akan mengubah keadaan internal kelas. Ini adalah konsep yang kuat tetapi sebenarnya tidak dapat diberlakukan di C ++. Ini lebih dari janji daripada jaminan. Dan yang sering rusak dan mudah pecah.

foobar& fbNonConst = const_cast<foobar&>(fb1);
JaredPar
sumber
3
Saya pikir jawabannya adalah tentang metode const lainnya dan bukan tentang objek const.
Mykola Golubyev
Terima kasih untuk "Gagasan di balik constini adalah untuk menandai metode yang tidak akan mengubah keadaan internal kelas". Itu benar-benar yang saya cari.
kovac
1
@JaredPar apakah ini berarti bahwa fungsi anggota yang mewakili operasi read-only harus ditandai sebagai const?
kovac
26

Const ini berarti bahwa compiler akan Error jika metode 'with const' mengubah data internal.

class A
{
public:
    A():member_()
    {
    }

    int hashGetter() const
    {
        state_ = 1;
        return member_;
    }
    int goodGetter() const
    {
        return member_;
    }
    int getter() const
    {
        //member_ = 2; // error
        return member_;
    }
    int badGetter()
    {
        return member_;
    }
private:
    mutable int state_;
    int member_;
};

Ujian

int main()
{
    const A a1;
    a1.badGetter(); // doesn't work
    a1.goodGetter(); // works
    a1.hashGetter(); // works

    A a2;
    a2.badGetter(); // works
    a2.goodGetter(); // works
    a2.hashGetter(); // works
}

Baca ini untuk informasi lebih lanjut

Mykola Golubyev
sumber
1
Pertanyaan tentang constfungsi anggota yang tidak menyebutkan bisa berubah tidak lengkap di terbaik.
IInspectable
13

Jawaban Blair tepat sasaran.

Namun perhatikan bahwa ada mutablekualifikasi yang dapat ditambahkan ke anggota data kelas. Setiap anggota yang ditandai dapat dimodifikasi dalam suatu constmetode tanpa melanggar constkontrak.

Anda mungkin ingin menggunakan ini (misalnya) jika Anda ingin objek mengingat berapa kali metode tertentu dipanggil, sementara tidak mempengaruhi keteguhan "logis" dari metode itu.

Alnitak
sumber
10

Arti Fungsi Anggota Konstituen dalam C ++ Pengetahuan Umum: Essential Intermediate Programming memberikan penjelasan yang jelas:

Jenis pointer ini dalam fungsi anggota non-const dari kelas X adalah X * const. Artinya, ini adalah pointer konstan ke X yang tidak konstan (lihat Const Pointers dan Pointers to Const [7, 21]). Karena objek yang dirujuk ini bukan const, ia dapat dimodifikasi. Jenis ini dalam fungsi anggota const dari kelas X adalah const X * const. Yaitu, ini adalah pointer konstan ke X konstan. Karena objek yang dirujuk ini adalah const, ia tidak dapat dimodifikasi. Itulah perbedaan antara fungsi anggota const dan non-const.

Jadi dalam kode Anda:

class foobar
{
  public:
     operator int () const;
     const char* foo() const;
};

Anda dapat menganggapnya sebagai ini:

class foobar
{
  public:
     operator int (const foobar * const this) const;
     const char* foo(const foobar * const this) const;
};
Nan Xiao
sumber
thistidak const. Alasan mengapa hal itu tidak dapat dimodifikasi adalah karena ini adalah nilai awal.
Brian
7

ketika Anda menggunakan constdalam tanda tangan metode (seperti kata const char* foo() const;Anda:) Anda memberi tahu kompiler bahwa memori yang ditunjuk oleh thistidak dapat diubah oleh metode ini (yang ada di foosini).

Matrix Buster
sumber
6

Saya ingin menambahkan poin berikut.

Anda juga bisa membuatnya menjadi const &danconst &&

Begitu,

struct s{
    void val1() const {
     // *this is const here. Hence this function cannot modify any member of *this
    }
    void val2() const & {
    // *this is const& here
    }
    void val3() const && {
    // The object calling this function should be const rvalue only.
    }
    void val4() && {
    // The object calling this function should be rvalue reference only.
    }

};

int main(){
  s a;
  a.val1(); //okay
  a.val2(); //okay
  // a.val3() not okay, a is not rvalue will be okay if called like
  std::move(a).val3(); // okay, move makes it a rvalue
}

Jangan ragu untuk meningkatkan jawabannya. Saya bukan ahli

coder3101
sumber
1
*thisselalu merupakan lvalue, bahkan jika fungsi anggota adalah rvalue-ref-kualifikasi dan dipanggil pada rvalue. Contoh .
HolyBlackCat
1
Ya, jadi bagaimana saya harus meningkatkan jawaban saya saat ini?
coder3101
Maksud saya apa yang harus ditulis dalam komentar di blok, yang membenarkan perilaku
coder3101
Diperbarui. Apakah itu tidak apa apa?
coder3101
2

Kata kunci const yang digunakan dengan deklarasi fungsi menetapkan bahwa itu adalah fungsi anggota const dan tidak akan dapat mengubah anggota data objek.

Chandra Shekhar
sumber
1

https://isocpp.org/wiki/faq/const-correctness#const-member-fns

Apa itu " constfungsi anggota"?

Fungsi anggota yang memeriksa (bukan bermutasi) objeknya.

Sebuah constfungsi anggota ditunjukkan dengan constakhiran setelah daftar parameter fungsi anggota ini. Fungsi anggota dengan constsufiks disebut "fungsi anggota konst" atau "pemeriksa." Fungsi anggota tanpa constakhiran disebut "fungsi anggota non-const" atau "mutators."

class Fred {
public:
  void inspect() const;   // This member promises NOT to change *this
  void mutate();          // This member function might change *this
};
void userCode(Fred& changeable, const Fred& unchangeable)
{
  changeable.inspect();   // Okay: doesn't change a changeable object
  changeable.mutate();    // Okay: changes a changeable object
  unchangeable.inspect(); // Okay: doesn't change an unchangeable object
  unchangeable.mutate();  // ERROR: attempt to change unchangeable object
}

Upaya untuk menelepon unchangeable.mutate()adalah kesalahan yang tertangkap saat kompilasi. Tidak ada ruang runtime atau penalti kecepatan untuk const, dan Anda tidak perlu menulis kasus uji untuk memeriksanya saat runtime.

Trailing constpada inspect()fungsi anggota harus digunakan untuk berarti metode tidak akan mengubah keadaan abstrak (terlihat klien) objek. Itu sedikit berbeda dari mengatakan metode tidak akan mengubah "bit mentah" dari struct objek. Kompiler C ++ tidak diizinkan untuk mengambil interpretasi "bitwise" kecuali mereka dapat memecahkan masalah aliasing, yang biasanya tidak dapat diselesaikan (yaitu, alias non-const bisa ada yang dapat mengubah keadaan objek). Wawasan (penting) lain dari masalah aliasing ini: menunjuk ke suatu objek dengan pointer-to-const tidak menjamin bahwa objek tidak akan berubah; itu hanya menjanjikan bahwa objek tidak akan berubah melalui pointer itu .

qwr
sumber