this in C++ [] (this in C++), Lektion, Seite 723352
https://www.purl.org/stefan_ram/pub/this_c++ (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram
C++-Kurs

»*this« – Das Zielobjekt in C++ 

Im letzten Programm der vorherigen Lektion wurde das Objekt »p« mit der folgenden Anweisung auf den Wert »{ 2, 3 }« gesetzt.

Anweisung
p.set( p, 2, 3 );

Es fällt auf, daß das Objekt »p« in jener Anweisung zwiefach angegeben wurde, und man kann sich fragen, ob diese doppelte Spezifikation wirklich nötig ist.

»p« steht einmal vor dem Punkt, um damit als das Zielobjekt  durch seine Klasse die Klasse anzugeben, in welcher die Funktion »set« gesucht werden soll. Es handelt sich ja um die Klasse »::pair«, also die Klasse von »p«.

»p« steht außerm auch noch in den Klammern, um damit als ein Argumentobjekt  das Objekt anzugeben, welches auf den Wert »{ 2, 3 }« gesetzt werden soll, nämlich »p«.

Diese erneute Angabe von »p« als Argumentobjekt, wäre nicht nötig, wenn man in der Funktion auf das Zielobjekt zugreifen könnte. Die Anweisung könnte dann wie folgt vereinfacht werden.

vereinfachte Anweisung
p.set( 2, 3 );

Tatsächlich können wir in einer nicht-statischen Methode auf das Zielobjekt zugreifen. Das Zielobjekt eines Aufrufs kann in einer nicht-statischen Methode durch den Ausdruck »( *this )« bezeichnet werden.

Damit können wir das ganze Programm aus der vorigen Lektion nun so umschreiben, daß es nicht mehr nötig ist, ein Argumentobjekt auch noch als Zielobjekt anzugeben.

main.cpp

#include <initializer_list>
#include <iostream>
#include <ostream>

struct pair
{ double x;
double y;

void set
( double const x,
double const y )
{ ( *this ).x = x;
( *this ).y = y; }

void add
( pair const & p )
{ ( *this ).x += p.x;
( *this ).y += p.y; }

pair sum
( pair const & p )
{ ( *this ).add( p );
return( *this ); }

void print()
{ ::std::cout <<( *this ).x << '\n';
::std::cout <<( *this ).y << '\n'; }};

int main()
{ pair p;
pair q;
p.set( 2, 3 );
q.set( 1, 4 );
p.sum( q ).print(); }

::std::cout
3
7

Externe Methoden einer Klasse

Das Programm ist so vollkommen korrekt, allerdings sieht der Aufruf »p.sum( q )« etwas merkwürdig aus, da die Summe zweier Paare eigentlich eine symmetrische Funktion beider Paare ist und es keinen Grund dafür gibt, ein Paar willkürlich als „Zielobjekt“ hervorzuheben. Daher entfernen wir die Funktion »sum« aus stilistischen Gründen aus dem Klassenspezifizierer.

Obwohl die Funktion »sum« nicht mehr innerhalb des Klassenspezifizierers definiert wird, sehen wir sie weiterhin als „Teil der Klasse“ an.

In C++  sieht man auch Funktionen, die nicht innerhalb des Klassenspezifizierers definiert werden, aber eine enge inhaltliche Zugehörigkeit zu einer Klasse aufweisen und „in der Nähe“ des Klassenspezifizierers definiert werden als Teil jener Klasse an. Aus stilistischen Gründen ist es in einigen Fällen besser, einige Funktionen, insbesondere solche, welche nicht direkt auf die Felder eines Objekts zugreifen müssen, außerhalb des Klassenspezifizierers zu deklarieren. Wir kommen damit zu dem folgenden Programm.

main.cpp

#include <initializer_list>
#include <iostream>
#include <ostream>

struct pair
{ double x;
double y;

void set
( double const x,
double const y )
{ ( *this ).x = x;
( *this ).y = y; }

void add
( pair const & p )
{ ( *this ).x += p.x;
( *this ).y += p.y; }

void print()
{ ::std::cout <<( *this ).x << '\n';
::std::cout <<( *this ).y << '\n'; }};

pair sum
( pair p,
pair const & q )
{ p.add( q );
return p; }

int main()
{ pair p;
pair q;
p.set( 2, 3 );
q.set( 1, 4 );
sum( p, q ).print(); }

::std::cout
3
7

const-Methoden einer Klasse

Methoden, welche das Zielobjekt nicht verändern, können und sollte mit einem »const« gekennzeichnet werden, welches in diesem Fall direkt vor den Methodenrumpf geschrieben wird.

main.cpp

#include <initializer_list>
#include <iostream>
#include <ostream>

struct pair
{ double x;
double y;

void set
( double const x,
double const y )
{ ( *this ).x = x;
( *this ).y = y; }

void add
( pair const & p )
{ ( *this ).x += p.x;
( *this ).y += p.y; }

void print() const
{ ::std::cout <<( *this ).x << '\n';
::std::cout <<( *this ).y << '\n'; }};

pair sum
( pair p,
pair const & q )
{ p.add( q );
return p; }

int main()
{ pair p;
pair q;
p.set( 2, 3 );
q.set( 1, 4 );
sum( p, q ).print(); }

::std::cout
3
7

Überladung bei const-Methoden einer Klasse

Das folgende Programm zeigt, daß zwei Funktionen in eine Klasse eingetragen werden können, die sich nur in ihrer Konstantheit unterscheiden.

Wird die Funktion für eine Variable aufgerufen, so wird dann beim Aufruf einer Funktion über eine nicht-konstante Variable die nicht-konstante Funktion bevorzugt, während beim Aufruf über eine konstante Variable die konstante Funktion bevorzugt wird.

main.cpp

#include <initializer_list>
#include <iostream>
#include <ostream>
#include <string>

using namespace ::std::literals;

struct s
{ void f() const
{ ::std::cout << "f() const\n"s; }
void f()
{ ::std::cout << "f()\n"s; }};

int main()
{ { s const c; c.f(); }
{ s v; v.f(); }}

::std::cout
f() const
f()

Abkürzende Schreibweisen

Als Abkürzung für »( *this ).x« kann auch »this->x« geschrieben werden, wobei an Stelle von »x« auch ein beliebiger anderer Name stehen kann.

Falls keine Verwechslungen mit anderen gleichnamigen Variablen möglich sind, kann an Stelle von »( *this ).x« auch einfach nur »x« geschrieben werden, wobei an Stelle von »x« auch ein beliebiger anderer Name stehen kann.

Wir zeigen ein früheres Programm im folgenden, wobei wir in der Funktion »set« einmal die abkürzenden Schreibweise mit einem Pfeil und in der Funktion »add« einmal die abkürzende Schreibweise mit dem bloßen Namen des Feldes verwenden.

main.cpp

#include <initializer_list>
#include <iostream>
#include <ostream>

struct pair
{ double x;
double y;

void set
( double const x,
double const y )
{ ( *this ).x = x;
this->y = y; }

void add
( pair const & p )
{ ( *this ).x += p.x;
y += p.y; }

pair sum
( pair const & p )
{ ( *this ).add( p );
return( *this ); }

void print()
{ ::std::cout <<( *this ).x << '\n';
::std::cout <<( *this ).y << '\n'; }};

int main()
{ pair p;
pair q;
p.set( 2, 3 );
q.set( 1, 4 );
p.sum( q ).print(); }

::std::cout
3
7

Übungsfragen

?   Ausgabe

Sagen Sie die Ausgabe des folgenden Programms voraus, ohne das Programm zu starten.

main.cpp

#include <initializer_list>
#include <iostream>
#include <ostream>

struct object
{ int x;
void m() const { ::std::cout <<( *this ).x << '\n'; }};

int main()
{ object const p{ 8 };
object const q{ 3 };

p.m();
q.m();
p.m(); }

?   Ziel- und Argumentobjekt

Wie heißt das Zielobjekt des folgenden Aufrufs?

Wie heißt das Argumentobjekt des folgenden Aufrufs?

Aufruf
gamma.m( delta );

?   Ausgabe

Sagen Sie die Ausgabe des folgenden Programms voraus, ohne das Programm zu starten.

main.cpp

#include <initializer_list>
#include <iostream>
#include <ostream>

struct object
{ int x;
void m( object const & other ) const
{ ::std::cout <<( *this ).x - other.x << '\n'; }};

int main()
{ object const p{ 9 };
object const q{ 5 };

p.m( q );
q.m( p ); }

?   Ausgabe (mittelschwierig)

Sagen Sie die Ausgabe des folgenden Programms voraus, ohne das Programm zu starten.

main.cpp

#include <initializer_list>
#include <iostream>
#include <ostream>

struct object
{ int x;

int a() const
{ return 14; }

int b() const
{ return( *this ).x; }

void m( object const & other ) const
{ ::std::cout <<( *this ).a() - other.b() << '\n'; }};

int main()
{ object const p{ 9 };
object const q{ 5 };

p.m( q );
q.m( p ); }

?   Ausgabe (mittelschwierig)

Sagen Sie die Ausgabe des folgenden Programms voraus, ohne das Programm zu starten.

main.cpp

#include <initializer_list>
#include <iostream>
#include <ostream>

struct object
{ int x;

void m()
{ ::std::cout <<( *this ).x++ << '\n'; }};

int main()
{ object p{ 9 };
object q{ 5 };

p.m();
q.m();
p.m(); }

Übungsaufgaben (Grundaufgaben I)

/   Getter (Inspector)

Deklarieren Sie in dem folgenden Programm an der Stelle der Lücke »« eine nicht-statische Methode »x()«, welche den Wert des Feldes »xval« zurückgibt!

(Die ersten fünf Zeilen und die letzten drei Zeilen sollten nicht verändert werden.)

main.cpp

#include <initializer_list>
#include <iostream>
#include <ostream>

struct object
{ int xval;

… };

int main()
{ { object const object{ 12 }; ::std::cout << object.x() << '\n'; }
{ object const object{ 17 }; ::std::cout << object.x() << '\n'; }}

::std::cout
12
17

/   Setter (Mutator)

Deklarieren Sie in dem folgenden Programm an der Stelle der Lücke »« eine nicht-statische Methode »x(int)«, welche den Wert des Arguments des Aufrufs von »x(int)« zum Wert des Feldes »xval« aus dem Zielobjektes macht!

(Die ersten beiden Zeilen und die letzten vier Zeilen sollten nicht verändert werden.)

main.cpp

#include <initializer_list>
#include <iostream>
#include <ostream>

struct object
{ int xval;

… };

int main()
{ { object object; object.x( 33 ); ::std::cout << object.xval << '\n'; }
{ object object; object.x( 2 ); ::std::cout << object.xval << '\n'; }}

::std::cout
33
2

Seiteninformationen und Impressum   |   Mitteilungsformular  |   "ram@zedat.fu-berlin.de" (ohne die Anführungszeichen) ist die Netzpostadresse von Stefan Ram.   |   Eine Verbindung zur Stefan-Ram-Startseite befindet sich oben auf dieser Seite hinter dem Text "Stefan Ram".)  |   Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram. Schlüsselwörter zu dieser Seite/relevant keywords describing this page: Stefan Ram Berlin slrprd slrprd stefanramberlin spellched stefanram723352 stefan_ram:723352 this in C++ Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd723352, slrprddef723352, PbclevtugFgrsnaEnz Erklärung, Beschreibung, Info, Information, Hinweis,

Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram.
https://www.purl.org/stefan_ram/pub/this_c++