Bir sınıfın işlev bildiriminde son olarak 'const' anlamı nedir?


728

Bunun constgibi deklarasyonlarda anlamı nedir ? constBeni karıştırır.

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

Yanıtlar:


952

constAnahtar kelimeyi bir yönteme eklediğinizde, thisişaretçi esasen constnesneye bir işaretçi olur ve bu nedenle üye verilerini değiştiremezsiniz. (Kullanmazsanız mutable, daha sonra daha fazla).

constAnahtar kelime, iki benzer yöntemler nesnedir çağrılan birini uygulamak anlamına gelir fonksiyonları imza parçasıdır constve olmayan birinin.

#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();
}

Bu çıktı

Foo
Foo const

Const olmayan yöntemde, constsürümde yapamayacağınız örnek üyelerini değiştirebilirsiniz . Yukarıdaki örnekteki yöntem bildirimini aşağıdaki koda değiştirirseniz bazı hatalar alırsınız.

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

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

Bu tamamen doğru değildir, çünkü bir üyeyi olarak işaretleyebilirsiniz mutableve bir constyöntem daha sonra bunu değiştirebilir. Daha çok dahili sayaçlar ve eşyalar için kullanılır. Bunun çözümü aşağıdaki kod olacaktır.

#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;
}

hangisi çıktı

Foo
Foo const
Foo has been invoked 2 times


47

constEleme aracı yöntemleri herhangi bir değer çağrılabilir foobar. Fark, bir const nesnesinde const olmayan bir yöntem çağırmayı düşündüğünüzde ortaya çıkar. Türünüzde foobaraşağıdaki ek yöntem bildirimi olup olmadığını göz önünde bulundurun :

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

Yöntem bar()sabit değildir ve yalnızca sabit olmayan değerlerden erişilebilir.

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

Ancak arkadaki fikir const, sınıfın iç durumunu değiştirmeyecek yöntemleri işaretlemektir. Bu güçlü bir kavramdır, ancak aslında C ++ ile uygulanamaz. Bu bir garantiden çok bir vaattir. Ve genellikle kırılan ve kolayca kırılan bir tane.

foobar& fbNonConst = const_cast<foobar&>(fb1);

3
Cevabın const nesneleriyle değil, diğer const yöntemleri ile ilgili olduğunu düşündüm.
Mykola Golubyev

" constGerçi buradaki fikir sınıfın iç durumunu değiştirmeyecek yöntemleri işaretlemektir " için teşekkürler . Aradığım şey gerçekten buydu.
kovac

1
@JaredPar, salt okunur bir işlemi temsil eden herhangi bir üye işlevinin işaretli olması gerektiği anlamına constmı gelir?
kovac

26

Bu sabit, 'const' yöntemi dahili verileri değiştirirse derleyicinin Hata vereceği anlamına gelir.

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_;
};

Test

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
}

Daha fazla bilgi için bunu okuyun


1
constÜye işlevleriyle ilgili değişken olmayan bir soru en iyi ihtimalle eksiktir.
Tahmin edilemeyen

13

Blair'in cevabı işaret üzerindedir.

Ancak, mutablesınıfın veri üyelerine eklenebilecek bir niteleyici olduğunu unutmayın . Böyle işaretlenmiş bir üyesi olabilir bir değiştirilebilir constihlal etmeden yöntemle constsözleşmesi.

Bir nesnenin belirli bir yöntemin kaç kez çağrıldığını hatırlamasını ve bu yöntemin "mantıksal" sabitliğini etkilememesini istiyorsanız (örneğin) bunu kullanmak isteyebilirsiniz.


10

Bir const üye Fonksiyon Anlamı de C ++ Ortak Bilgi: Essential Orta Programlama açıklama getiriyordu:

X sınıfının sabit olmayan bir üye işlevindeki bu işaretçinin türü X * sabitidir. Yani, sabit olmayan bir X'in sabit göstergesidir (bkz. Sabit İşaretçiler ve Sabit İşaretçiler [7, 21]). Bunun atıfta bulunduğu nesne sabit olmadığından değiştirilebilir. Bunun bir X sınıfının const üye fonksiyonundaki türü const X * const'tur. Yani, sabit bir X'in sabit göstergesidir. Bunun atıfta bulunduğu nesne sabit olduğundan, değiştirilemez. Sabit ve sabit olmayan üye işlevleri arasındaki fark budur.

Yani kodunuzda:

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

Bunu şöyle düşünebilirsiniz:

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

thisdeğil const. Değiştirilememesinin nedeni, bir ön değer olmasıdır.
Brian

7

kullandığınızda constyöntem imzası (sınırlamasına uyan ki: const char* foo() const;) bellek tarafından işaret olduğu derleyici anlatıyorsun this(ki bu yöntemle değiştirilemez fooburada).


6

Aşağıdaki noktayı eklemek istiyorum.

Ayrıca bir const &veconst &&

Yani,

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
}

Cevabı geliştirmekten çekinmeyin. Ben uzman değilim


1
*thisüye işlevi rvalue-ref-nitelikli olsa ve bir rvalue olarak çağrılsa bile her zaman bir lvalue'dur. Örnek .
HolyBlackCat

1
Evet, mevcut cevabımı nasıl geliştirmeliyim?
coder3101

Bu, blokta yorumda ne yazacağımı kastediyorum, bu davranışı haklı
çıkarıyor

Güncellenmiş. Uygun mu?
coder3101

2

Const bir olduğunu fonksiyon beyan belirttiği birlikte kullanılan anahtar kelime const üye işlev ve edecektir değiştirmek mümkün olmayacaktır nesnenin veri üyeleri.


1

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

" constÜye işlevi" nedir?

Nesnesini inceleyen (değiştiren) bir üye işlevi.

Bir constüye işlevi ile belirtilir constsadece üye işlevin parametre listesinden sonra son eki. Bir ile üye fonksiyonları constsoneki “const üye işlevler” veya denir “müfettişler.” Bir olmadan Üyesi fonksiyonları constsoneki “const olmayan üye işlevler” veya denir “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
}

Arama denemesi unchangeable.mutate()derleme zamanında yakalanan bir hatadır. Çalışma zamanı alanı veya hız cezası yoktur ve çalışma zamanında constkontrol etmek için test senaryoları yazmanıza gerek yoktur.

Üye işlevi constüzerindeki iz inspect(), yöntemin nesnenin soyut (istemci tarafından görülebilir) durumunu değiştirmeyeceği anlamına gelmelidir . Bu, yöntemin nesnenin yapısının “ham bitlerini” değiştirmeyeceğini söylemekten biraz farklıdır. C ++ derleyicilerinin, normal olarak çözülemeyen örtüşme sorununu çözemedikleri sürece "bitsel" yorumunu almasına izin verilmez (yani, nesnenin durumunu değiştirebilecek sabit olmayan bir diğer ad bulunabilir). Bu diğer adlandırma sorunundan başka bir (önemli) öngörü: işaretçiden-kanala sahip bir nesneye işaret etmek nesnenin değişmeyeceğini garanti etmez; yalnızca nesnenin bu işaretçi aracılığıyla değişmeyeceğine söz verir .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.