Jste zde

Zajímavosti z C++: Kdy je potřeba použít klíčové slovo 'this'

Troufám si tvrdit, že většina programátorů o klíčovém slovu this slyšela a ví, že se jedná o automaticky zpřístupněný ukazatel v metodě, který ukazuje na objekt, na kterém byla metoda zavolána. Obvykle se s tímto klíčovým slovem nesetkáte, protože když v metodě voláte jiné metody či přistupujete na datové složky objektu, tak je onen ukazatel implicitní. Jsou ovšem situace, ve kterých je použití tohoto klíčového slova nutné. A o těchto situacích bude následující příspěvek.

Co je to klíčové slovo this?

Klíčové slovo this lze v C++ použít v definicích metod, kde slouží k přístupu k objektu, na kterém byla metoda zavolána. Dá se na něj dívat jako na nultý parametr, který se automaticky předává všem volaným metodám. Pokud by tato podpora v C++ chyběla, museli byste si ukazatel na objekt předávat sami, což by značně znepřehlednilo kód. Typem this je ukazatel na aktuální objekt (či konstantní/volatile ukazatel, pokud se jedná o konstantní/volatile metodu).

Hlavní důvod, proč se s tímto klíčovým slovem příliš nesetkáváte, je ten, že jeho použití je mnohdy pouze volitelné. Skutečně, pokud v metodě voláte jinou metodu či přistupujete k datové složce, tak za vás volání přes this vyřeší překladač. To nás přivádí k následující otázce.

Kdy je potřeba jej použít?

Existují situace, ve kterých klíčové slovo this použít musíte. Zde je seznam některých z nich.

(1) Potřebujete v metodě někam předat ukazatel na objekt, na kterém byla metoda zavolána

Často se to používá při implementaci návrhového vzoru Visitor. Příklad:

class AddExpr {
public:
    // ...
 
    void accept(Visitor *v) {
        v->visit(this);
    }
}

Jako kuriozitu tu pak máme harakiri ve stylu C++ :).

delete this;

Pokud by vás zajímalo využití, tak mrkněte zde. Zde je pak k dispozici seznam věcí, na které si musíte dát při použití této konstrukce pozor.

(2) Potřebujete v metodě někam předat objekt, na kterém byla metoda zavolána

Toto využití this vídáme v implementacích operátoru přiřazení, který vrací referenci na objekt, do kterého se přiřazuje. Níže je ukázka implementace tohoto operátoru pomocí copy & swap idiomu.

T & operator=(T o) {  // T zde musí být předáno hodnotou
    swap(*this, o);
    return *this;
}

(3) Existuje proměnná se stejným názvem jako datová složka

V následujícím kódu je použití this nutné.

class Wrapper {
public:
    void wrap(int width) {
        this->width = width;
 
        // ..
    }
 
private:
    int width;
};

Bez něj by totiž došlo k přiřazení parametru do sebe sama. Klíčové slovo this zde slouží k rozlišení, zda se přistupuje k parametru funkce či k datové složce objektu. Obdobný problém nastává v případě kolizí názvů lokálních proměnných a metod.

Pokud se však v této situaci jedná o inicializační část konstruktoru, pak this použít nemusíte:

class MyNum {
public:
    MyNum(int value, int bitWidth): value(value), bitWidth(bitWidth) {
        // ..
    }
 
private:
    int value;
    int bitWidth;
};

Překladač se automaticky postará o to, aby kód dělal přesně to, co očekáváte, čili nainicializoval datové složky pomocí hodnot parametrů.

(4) Voláte v podtřídě metodu z šablonové nadtřídy

Kvůli způsobu vyhledávání jmen (name lookup) v C++ musíte v následujícím příkladu před voláním f() v podtřídě použít this.

template <typename T>
class A {
protected:
    void f() {
        // ...
    }
};
 
template <typename T>
class B: A<T> {
public:
    void g() {
        this->f();  // zde musí být this->
    }
};

V opačném případě vám bude překladač hlásit chybu (poznámka: starší verze gcc chybu v tomto případě nehlásily).

Pokud by vás zajímaly detaily, tak mrkněte např. zde. Obdobná situace nastává v případě, když přistupujete k členské proměnné z nadtřídy, která je šablona. Související odkaz na FAQ je zde (je tam uveden i způsob, jak toto vyřešit bez použití this).

Je to vše?

Seznam výše zřejmě nebude vyčerpávající. Pokud víte o nějaké další situaci, ve které je třeba klíčové slovo this použít, nezapomeňte se podělit v komentáři!

Přidat komentář