Chris Codeblog

Tipps, Tricks & Tutorials rund ums Programmieren

[C++] Das const Keyword

Ich selbst habe mich lange davor gedrückt, aber irgendwann wurde es doch Zeit mich mit dem const-Keyword in C++ außeinanderzusetzen. Und um dieses Keyword soll es in diesem Beitrag auch gehen.

Was ist const?

Was ist constund wozu braucht man es? Naja, constsagt einfach nur aus, dass eine Variable nicht verändert werden darf. Oder dass eine Funktion die Daten nicht verändert. Nun gibt es in C++ aber auch Pointer und das macht das ganze etwas komplizierter.

const ist ein Trailing-Keyword

Das heißt es steht immer hinter dem Code, auf den es sich bezieht.

Beispiel:

// const bezieht sich auf den Typ (int)
int const *i;
// const bezieht sich auf den Pointer
int * const i;
// das erste const bezieht sich auf den Typ (int), das zweite auf den Pointer
int const * const i;

Am besten liest man das ganze von rechts nach links:

  • Zeile 2: i ist ein Pointer auf const int
  • Zeile 4: i ist ein const Pointer auf int
  • Zeile 6: i ist ein const Pointer auf const int

Ihr habt bestimmt auch schon die Schreibweise const int i oder const int &i gesehen. Warum steht hier const vor dem Typen, obwohl es sich um ein Trailing-Keyword handelt?

Da sich links vom Typen nichts mehr befindet, kann sich const auch auf nichts anderes beziehen. In dem Fall darf const also auch links vom Typ stehen. Folgende beiden Zeilen sind also gleichbedeutend:

const int i;
int const i;

const bei Variablen und Pointern

Sehen wir uns ein paar Beispiele für das const Keyword bei Pointern und Variablen an:

// const int:
//-------------------------------------------
int const i = 5;
// Fehler: Der int ist const und kann somit nicht geaendert werden
i = 10;

// const Pointer auf int
//-------------------------------------------
int * const i = new int(5);
// Erfolg: Nur der Pointer ist const, der Wert des int kann somit geaendert werden
*i = 10;
// Fehler: Der Pointer ist const und kann deshalb nicht geaendert werden
i = new int(10);

// Pointer auf const int
//-------------------------------------------
int const * i = new int(5);
// Erfolg
i = new int(10);
// Fehler
*i = 10;

// const Pointer auf einen const int:
//-------------------------------------------
int * const * i = new int(5);
// Fehler: int ist const und darf nicht geaendert werden
*i = 10;
// Fehler: Der Pointer ist ebenfalls const und darf nicht geaendert werden
i = new int(10);

Das ganze funktioniert logischerweise auch mit Smart-Pointern. Hier mal am Beispiel eines unique_ptr:

std::unique_ptr<int const> p = std::make_unique<int>(5);
// Erfolg
p = std::make_unique<int>(10);
// Fehler
*p = 10;

std::unique_ptr<int const> const p = std::make_unique<int>(5);
// Fehler
p = std::make_unique<int>(10);
// Fehler
*p = 10;

Was ist mit Funktionen?

Auch Funktionen, die Daten nicht verändern sollten als const gekennzeichnet werden um const-correctness zu „erreichen“. Wird eine Funktion, die keine Daten verändert nicht als const gekennzeichnet, kann sie auch nicht von anderen Funktionen aufgerufen werden, die als const gekennzeichnet wurden.

Ein kleines Beispiel:

class Person {
private:
    std::string name_{""};

public:
    Person(std::string name)
    : name_(name) {}

    void print() {
        std::cout << this->name_ << std::endl;
    }
  
    void printConst() const {
        std::cout << this->name_ << std::endl;
    }
};

// Erfolg: Person in printPerson + Person::print ist beides nicht const
void printPerson(Person &person) {
    person.print();
}

// Fehler: Person in printPerson ist const, Person::print aber nicht
void printPerson(const Person &person) {
    person.print();
}

// Erfolg: Person in printPerson ist const, Person::printConst ist ebenfalls const
void printPerson(const Person &person) {
    person.printConst();
}

Es gibt übrigens auch die Möglichkeit die Funktion zwei mal (einmal const, einmal nicht const) zu definieren. Der Compiler wählt denn die entsprechend benötigte Funktion:

class Person {
private:
    std::string name_{""};
    bool printed_{false};

public:
    Person(std::string name)
    : name_(name) {}

    void print() {
        std::cout << this->name_ << std::endl;
        this->printed_ = true;
        std::cout << this->printed_ << std::endl;
    }

    void print() const {
        std::cout << this->name_ << std::endl;
        std::cout << this->printed_ << std::endl;
    }
};
[C++] Das const Keyword

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Nach oben scrollen