Namensräume
Varianten
Aktionen

Nicht-statische Memberfunktionen

Von cppreference.com
< cpp‎ | Sprache
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 
 

Eine nicht-statische Memberfunktion ist eine Funktion, die in einer Member-Spezifikation einer Klasse deklariert ist, ohne einen static oder friend-Spezifizierer (siehe statische Memberfunktionen und friend-Deklaration für die Auswirkung dieser Schlüsselwörter).

class S
{
    int mf1(); // non-static member function declaration
    void mf2() volatile, mf3() &&; // can have cv-qualifiers and/or a reference-qualifier
        // the declaration above is equivalent to two separate declarations:
        // void mf2() volatile;
        // void mf3() &&;
 
    int mf4() const { return data; } // can be defined inline
    virtual void mf5() final; // can be virtual, can use final/override
    S() : data(12) {} // constructors are member functions too
    int data;
};
 
int S::mf1() { return 7; } // if not defined inline, has to be defined at namespace

Konstruktoren, Destruktoren und Konvertierungsfunktionen verwenden spezielle Syntaxen für ihre Deklarationen. Die auf dieser Seite beschriebenen Regeln gelten möglicherweise nicht für diese Funktionen. Einzelheiten finden Sie auf den jeweiligen Seiten.

Eine explizite Objekt-Memberfunktion ist eine nicht-statische Memberfunktion mit einem expliziten Objektparameter.

(seit C++23)

Eine implizite Objekt-Memberfunktion ist eine nicht-statische Memberfunktion ohne expliziten Objektparameter (vor C++23 war dies die einzige Art von nicht-statischer Memberfunktion und wurde daher in der Literatur als "nicht-statische Memberfunktion" bezeichnet).

Inhalt

[bearbeiten] Erläuterung

Alle Funktionsdeklarationen sind zulässig, mit zusätzlichen Syntaxelementen, die nur für nicht-statische Memberfunktionen verfügbar sind: reine Spezifizierer, cv-Qualifizierer, Ref-Qualifizierer, final und override Spezifizierer(seit C++11) und Member-Initialisierungslisten.

Eine nicht-statische Memberfunktion der Klasse X kann aufgerufen werden

1) Für ein Objekt vom Typ X unter Verwendung des Klassen-Member-Zugriffsoperators
2) Für ein Objekt einer Klasse, die von X abgeleitet ist
3) Direkt aus dem Körper einer Memberfunktion von X
4) Direkt aus dem Körper einer Memberfunktion einer von X abgeleiteten Klasse

Der Aufruf einer nicht-statischen Memberfunktion der Klasse X für ein Objekt, das nicht vom Typ X oder einer von X abgeleiteten Klasse ist, führt zu undefiniertem Verhalten.

Innerhalb des Körpers einer nicht-statischen Memberfunktion von X wird jeder id-Ausdruck e (z. B. ein Bezeichner), der sich zu einem Nicht-Typ-Nicht-Statik-Member von X oder einer Basisklasse von X auflöst, in einen Member-Zugriffsausdruck (*this).e umgewandelt (es sei denn, er ist bereits Teil eines Member-Zugriffsausdrucks). Dies geschieht nicht im Kontext von Vorlagendefinitionen, daher muss ein Name möglicherweise explizit mit this-> präfixiert werden, um abhängig zu werden.

struct S
{
    int n;
    void f();
};
 
void S::f()
{
    n = 1; // transformed to (*this).n = 1;
}
 
int main()
{
    S s1, s2;
    s1.f(); // changes s1.n
}

Innerhalb des Körpers einer nicht-statischen Memberfunktion von X wird jeder nicht qualifizierte Bezeichner, der sich zu einem statischen Member, einem Enumerator oder einem verschachtelten Typ von X oder einer Basisklasse von X auflöst, in den entsprechenden qualifizierten Bezeichner umgewandelt.

struct S
{
    static int n;
    void f();
};
 
void S::f()
{
    n = 1; // transformed to S::n = 1;
}
 
int main()
{
    S s1, s2;
    s1.f(); // changes S::n
}

[bearbeiten] Memberfunktionen mit cv-Qualifizierern

Eine implizite Objekt-Memberfunktion kann mit einer cv-Qualifiziersequenz (const, volatile oder einer Kombination aus const und volatile) deklariert werden. Diese Sequenz erscheint nach der Parameterliste in der Funktionsdeklaration. Funktionen mit unterschiedlichen cv-Qualifiziersequenzen (oder keiner Sequenz) haben unterschiedliche Typen und können sich daher gegenseitig überladen.

Im Körper einer Funktion mit einer cv-Qualifiziersequenz ist *this cv-qualifiziert, z. B. in einer Memberfunktion mit const-Qualifizierer dürfen nur andere Memberfunktionen mit const-Qualifizierer normal aufgerufen werden. Eine Memberfunktion ohne const-Qualifizierer kann immer noch aufgerufen werden, wenn const_cast angewendet wird oder über einen Zugriffspfad, der this nicht einschließt.

#include <vector>
 
struct Array
{
    std::vector<int> data;
    Array(int sz) : data(sz) {}
 
    // const member function
    int operator[](int idx) const
    {                     // the this pointer has type const Array*
        return data[idx]; // transformed to (*this).data[idx];
    }
 
    // non-const member function
    int& operator[](int idx)
    {                     // the this pointer has type Array*
        return data[idx]; // transformed to (*this).data[idx]
    }
};
 
int main()
{
    Array a(10);
    a[1] = 1;  // OK: the type of a[1] is int&
    const Array ca(10);
    ca[1] = 2; // Error: the type of ca[1] is int
}

Memberfunktionen mit Ref-Qualifizierern

Eine implizite Objekt-Memberfunktion kann ohne Ref-Qualifizierer, mit einem Lvalue-Ref-Qualifizierer (das Token & nach der Parameterliste) oder dem Rvalue-Ref-Qualifizierer (das Token && nach der Parameterliste) deklariert werden. Während der Überladungsauflösung wird eine implizite Objekt-Memberfunktion mit einer cv-Qualifiziersequenz der Klasse X wie folgt behandelt:

  • kein Ref-Qualifizierer: Der implizite Objektparameter hat den Typ Lvalue-Referenz auf cv-qualifiziertes X und darf zusätzlich ein Rvalue-Implizites-Objektargument binden
  • Lvalue-Ref-Qualifizierer: Der implizite Objektparameter hat den Typ Lvalue-Referenz auf cv-qualifiziertes X
  • Rvalue-Ref-Qualifizierer: Der implizite Objektparameter hat den Typ Rvalue-Referenz auf cv-qualifiziertes X
#include <iostream>
 
struct S
{
    void f() &  { std::cout << "lvalue\n"; }
    void f() && { std::cout << "rvalue\n"; }
};
 
int main()
{
    S s;
    s.f();            // prints "lvalue"
    std::move(s).f(); // prints "rvalue"
    S().f();          // prints "rvalue"
}

Hinweis: Im Gegensatz zur cv-Qualifizierung ändert die Ref-Qualifizierung nicht die Eigenschaften des this-Zeigers: Innerhalb einer Rvalue-Ref-qualifizierten Funktion ist *this immer noch ein Lvalue-Ausdruck.

(seit C++11)

[bearbeiten] Virtuelle und reine virtuelle Funktionen

Eine nicht-statische Memberfunktion kann als virtuell oder rein virtuell deklariert werden. Details finden Sie unter virtuelle Funktionen und abstrakte Klassen.

Explizite Objekt-Memberfunktionen

Für eine nicht-statische, nicht-virtuelle Memberfunktion, die nicht mit cv-Qualifizierer oder Ref-Qualifizierer deklariert ist, kann ihr erster Parameter, falls es sich nicht um einen Funktionsparameterpaket handelt, ein expliziter Objektparameter sein (gekennzeichnet mit dem Präfix-Schlüsselwort this).

struct X
{
    void foo(this X const& self, int i); // same as void foo(int i) const &;
//  void foo(int i) const &; // Error: already declared
 
    void bar(this X self, int i); // pass object by value: makes a copy of “*this”
};

Für Memberfunktionsvorlagen ermöglicht der explizite Objektparameter die Ableitung von Typ und Wertkategorie. Dieses Sprachmerkmal wird als "deducing this" bezeichnet.

struct X
{
    template<typename Self>
    void foo(this Self&&, int);
};
 
struct D : X {};
 
void ex(X& x, D& d)
{
    x.foo(1);       // Self = X&
    move(x).foo(2); // Self = X
    d.foo(3);       // Self = D&
}

Dies macht es möglich, konstante und nicht-konstante Memberfunktionen zu deduplizieren. Siehe Array-Subskriptionsoperator als Beispiel.

Innerhalb des Körpers einer expliziten Objekt-Memberfunktion kann der this-Zeiger nicht verwendet werden: Alle Memberzugriffe müssen über den ersten Parameter erfolgen, wie bei statischen Memberfunktionen.

struct C
{
    void bar();
 
    void foo(this C c)
    {
        auto x = this; // error: no this
        bar();         // error: no implicit this->
        c.bar();       // ok
    }
};

Ein Zeiger auf eine explizite Objekt-Memberfunktion ist ein gewöhnlicher Funktionszeiger, kein Memberzeiger.

struct Y 
{
    int f(int, int) const&;
    int g(this Y const&, int, int);
};
 
auto pf = &Y::f;
pf(y, 1, 2);              // error: pointers to member functions are not callable
(y.*pf)(1, 2);            // ok
std::invoke(pf, y, 1, 2); // ok
 
auto pg = &Y::g;
pg(y, 3, 4);              // ok
(y.*pg)(3, 4);            // error: “pg” is not a pointer to member function
std::invoke(pg, y, 3, 4); // ok
(seit C++23)

[bearbeiten] Spezielle Memberfunktionen

Einige Memberfunktionen sind speziell: Unter bestimmten Umständen werden sie vom Compiler definiert, auch wenn sie nicht vom Benutzer definiert wurden. Dies sind:

(seit C++11)
(seit C++11)

Spezielle Memberfunktionen sowie die Vergleichsoperatoren(seit C++20) sind die einzigen Funktionen, die standardmäßig definiert werden können, d. h. mit = default anstelle des Funktionskörpers (Einzelheiten finden Sie auf ihren Seiten).

[bearbeiten] Anmerkungen

Feature-Testmakro Wert Std Feature
__cpp_ref_qualifiers 200710L (C++11) Referenz-Qualifizierer
__cpp_explicit_this_parameter 202110L (C++23) expliziter Objektparameter (deducing this)

[bearbeiten] Beispiel

#include <exception>
#include <iostream>
#include <string>
#include <utility>
 
struct S
{
    int data;
 
    // simple converting constructor (declaration)
    S(int val);
 
    // simple explicit constructor (declaration)
    explicit S(std::string str);
 
    // const member function (definition)
    virtual int getData() const { return data; }
};
 
// definition of the constructor
S::S(int val) : data(val)
{
    std::cout << "ctor1 called, data = " << data << '\n';
}
 
// this constructor has a catch clause
S::S(std::string str) try : data(std::stoi(str))
{
    std::cout << "ctor2 called, data = " << data << '\n';
}
catch(const std::exception&)
{
    std::cout << "ctor2 failed, string was '" << str << "'\n";
    throw; // ctor's catch clause should always rethrow
}
 
struct D : S
{
    int data2;
    // constructor with a default argument
    D(int v1, int v2 = 11) : S(v1), data2(v2) {}
 
    // virtual member function
    int getData() const override { return data * data2; }
 
    // lvalue-only assignment operator
    D& operator=(D other) &
    {
        std::swap(other.data, data);
        std::swap(other.data2, data2);
        return *this;
    }
};
 
int main()
{
    D d1 = 1;
    S s2("2");
 
    try
    {
        S s3("not a number");
    }
    catch(const std::exception&) {}
 
    std::cout << s2.getData() << '\n';
 
    D d2(3, 4);
    d2 = d1;   // OK: assignment to lvalue
//  D(5) = d1; // ERROR: no suitable overload of operator=
}

Ausgabe

ctor1 called, data = 1
ctor2 called, data = 2
ctor2 failed, string was 'not a number'
2
ctor1 called, data = 3

[bearbeiten] Defect Reports

Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR angewendet auf Verhalten wie veröffentlicht Korrigiertes Verhalten
CWG 194 C++98 unklar, ob eine nicht-statische Memberfunktion
denselben Namen wie der umschließende Klassenname haben könnte
Einschränkung der expliziten Benennung hinzugefügt

[bearbeiten] Siehe auch