Szukaj…


Składnia

  • const Typ myVariable = initial; // Deklaruje zmienną const; nie może zostać zmieniony
  • const Type & myReference = myVariable; // Deklaruje odniesienie do zmiennej const
  • const Typ * myPointer = & myVariable; // Deklaruje wskaźnik do stałej. Wskaźnik może się zmienić, ale nie można zmienić podstawowego elementu danych za pomocą wskaźnika
  • Wpisz * const myPointer = & myVariable; // Deklaruje stały wskaźnik. Nie można ponownie przypisać wskaźnika, aby wskazywał na coś innego, ale element danych będący podstawą może zostać zmieniony
  • const Typ * const myPointer = & myVariable; // Deklaruje stałą wskaźnik do stałej.

Uwagi

Zmiennej oznaczonej jako const nie można zmienić 1 . Próba wywołania na nim jakichkolwiek operacji non-const spowoduje błąd kompilatora.

1: Cóż, można to zmienić za pomocą const_cast , ale prawie nigdy nie powinieneś tego używać

Stałe zmienne lokalne

Deklaracja i wykorzystanie.

// a is const int, so it can't be changed
const int a = 15;  
a = 12;           // Error: can't assign new value to const variable
a += 1;           // Error: can't assign new value to const variable

Wiązanie referencji i wskaźników

int &b = a;       // Error: can't bind non-const reference to const variable
const int &c = a; // OK; c is a const reference

int *d = &a;      // Error: can't bind pointer-to-non-const to const variable
const int *e = &a // OK; e is a pointer-to-const

int f = 0;
e = &f;           // OK; e is a non-const pointer-to-const,
                  // which means that it can be rebound to new int* or const int*

*e = 1            // Error: e is a pointer-to-const which means that
                  // the value it points to can't be changed through dereferencing e

int *g = &f;
*g = 1;           // OK; this value still can be changed through dereferencing
                  // a pointer-not-to-const

Stałe wskaźniki

int a = 0, b = 2;

const int* pA = &a; // pointer-to-const. `a` can't be changed through this
int* const pB = &a; // const pointer. `a` can be changed, but this pointer can't.
const int* const pC = &a; // const pointer-to-const.

//Error: Cannot assign to a const reference
*pA = b;

pA = &b;

*pB = b;

//Error: Cannot assign to const pointer
pB = &b;

//Error: Cannot assign to a const reference
*pC = b;

//Error: Cannot assign to const pointer
pC = &b;

Funkcje składowe stałej

Funkcje składowe klasy można zadeklarować jako const , co informuje kompilator i przyszłych czytelników, że ta funkcja nie zmodyfikuje obiektu:

class MyClass
{
private:
    int myInt_;
public:
    int myInt() const { return myInt_; }
    void setMyInt(int myInt) { myInt_ = myInt; }
};

W funkcji const this wskaźnik jest faktycznie const MyClass * zamiast MyClass * . Oznacza to, że nie można zmieniać żadnych zmiennych składowych w ramach funkcji; kompilator wyśle ostrzeżenie. Tak więc setMyInt nie mógł zostać zadeklarowany jako const .

Prawie zawsze powinieneś oznaczać funkcje const jako const jeśli to możliwe. Tylko const funkcje const mogą być wywoływane na const MyClass .

metod static nie można zadeklarować jako const . Jest tak, ponieważ metoda statyczna należy do klasy i nie jest wywoływana na obiekcie; dlatego nigdy nie może modyfikować wewnętrznych zmiennych obiektu. Dlatego deklarowanie metod static jako const byłoby zbędne.

Unikanie powielania kodu w metodach const i non-const getter.

W metodach C ++, które różnią się tylko kwalifikatorem const można przeciążać. Czasami mogą być potrzebne dwie wersje gettera, które zwracają odniesienie do jakiegoś członka.

Niech Foo będzie klasą, która ma dwie metody, które wykonują identyczne operacje i zwraca odwołanie do obiektu typu Bar :

class Foo
{
public:
    Bar& GetBar(/* some arguments */)
    {
        /* some calculations */
        return bar;
    }
    
    const Bar& GetBar(/* some arguments */) const
    {
        /* some calculations */
        return bar;
    }

    // ...
};

Jedyna różnica między nimi polega na tym, że jedna metoda nie jest stała i zwraca odwołanie inne niż stałe (które można wykorzystać do modyfikacji obiektu), a druga to stała i zwraca stałe odniesienie.

Aby uniknąć powielania kodu, istnieje pokusa, aby wywołać jedną metodę z drugiej. Nie możemy jednak wywołać metody non-const z const. Ale możemy wywołać metodę const z metody non-const. Będzie to wymagać użycia „const_cast” do usunięcia kwalifikatora const.

Rozwiązaniem jest:

struct Foo
{
    Bar& GetBar(/*arguments*/)
    {
        return const_cast<Bar&>(const_cast<const Foo*>(this)->GetBar(/*arguments*/));
    }
    
    const Bar& GetBar(/*arguments*/) const
    {
        /* some calculations */
        return foo;
    }
};

W powyższym kodzie wywołujemy GetBar wersję GetBar z non-const GetBar , przesyłając to do typu const: const_cast<const Foo*>(this) . Ponieważ wywołujemy metodę const z non-const, sam obiekt jest non-const, a odrzucanie const jest dozwolone.

Przeanalizuj następujący, bardziej kompletny przykład:

#include <iostream>

class Student
{
public:
    char& GetScore(bool midterm)
    {
        return const_cast<char&>(const_cast<const Student*>(this)->GetScore(midterm));
    }
    
    const char& GetScore(bool midterm) const
    {
        if (midterm)
        {
            return midtermScore;
        }
        else
        {
            return finalScore;
        }
    }
    
private:
    char midtermScore;
    char finalScore;
};

int main()
{
    // non-const object
    Student a; 
    // We can assign to the reference. Non-const version of GetScore is called
    a.GetScore(true) = 'B';
    a.GetScore(false) = 'A';
    
    // const object
    const Student b(a); 
    // We still can call GetScore method of const object,
    // because we have overloaded const version of GetScore
    std::cout << b.GetScore(true) << b.GetScore(false) << '\n'; 
}


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow