Namespaces
Variants

Non-static member functions

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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

class S
{
    int mf1(); // Deklaration einer nicht-statischen Member-Funktion
    void mf2() volatile, mf3() &&; // kann CV-Qualifizierer und/oder Referenzqualifizierer haben
        // die obige Deklaration entspricht zwei separaten Deklarationen:
        // void mf2() volatile;
        // void mf3() &&;
    int mf4() const { return data; } // kann inline definiert werden
    virtual void mf5() final; // kann virtuell sein, kann final/override verwenden
    S() : data(12) {} // Konstruktoren sind ebenfalls Member-Funktionen
    int data;
};
int S::mf1() { return 7; } // wenn nicht inline definiert, muss im Namespace definiert werden

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. Weitere Einzelheiten finden Sie auf den jeweiligen Seiten.

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

(since C++23)

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

Inhaltsverzeichnis

Erklärung

Jede Funktionsdeklaration ist erlaubt, mit zusätzlichen Syntaxelementen, die nur für nicht-statische Memberfunktionen verfügbar sind: Pure-Specifiers , CV-Qualifiers , Ref-Qualifiers, final und override Specifiers (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 Hauptteil einer Memberfunktion von X
4) Direkt aus dem Hauptteil einer Memberfunktion einer von X abgeleiteten Klasse

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

Im Rumpf einer nicht-statischen Memberfunktion von X wird jeder Id-Ausdruck e (z.B. ein Bezeichner), der zu einem Nicht-Typ-Nicht-Statischen-Member von X oder einer Basisklasse von X aufgelöst wird, in einen Member-Zugriffsausdruck ( * this ) . e transformiert (sofern er nicht bereits Teil eines Member-Zugriffsausdrucks ist). Dies tritt nicht im Template-Definitionskontext auf, sodass ein Name explizit mit this - > präfixiert werden muss, um abhängig zu werden.

struct S
{
    int n;
    void f();
};
void S::f()
{
    n = 1; // umgewandelt zu (*this).n = 1;
}
int main()
{
    S s1, s2;
    s1.f(); // ändert s1.n
}

Im Rumpf einer nicht-statischen Memberfunktion von X wird jeder unqualifizierte Bezeichner, der zu einem statischen Member, einem Enumerator oder einem geschachtelten Typ von X oder einer Basisklasse von X aufgelöst wird, in den entsprechenden qualifizierten Bezeichner transformiert:

struct S
{
    static int n;
    void f();
};
void S::f()
{
    n = 1; // umgewandelt zu S::n = 1;
}
int main()
{
    S s1, s2;
    s1.f(); // ändert S::n
}

Memberfunktionen mit cv-Qualifizierern

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

Im Rumpf einer Funktion mit einer CV-Qualifizierer-Sequenz ist * this CV-qualifiziert, z.B. in einer Elementfunktion mit const -Qualifizierer können nur andere Elementfunktionen mit const -Qualifizierer normal aufgerufen werden. Eine Elementfunktion ohne const -Qualifizierer kann dennoch aufgerufen werden, wenn const_cast angewendet wird oder über einen Zugriffspfad, der nicht this beinhaltet.

#include <vector>
struct Array
{
    std::vector<int> data;
    Array(int sz) : data(sz) {}
    // konstante Member-Funktion
    int operator[](int idx) const
    {                     // der this-Zeiger hat den Typ const Array*
        return data[idx]; // transformiert zu (*this).data[idx];
    }
    // nicht-konstante Member-Funktion
    int& operator[](int idx)
    {                     // der this-Zeiger hat den Typ Array*
        return data[idx]; // transformiert zu (*this).data[idx]
    }
};
int main()
{
    Array a(10);
    a[1] = 1;  // OK: der Typ von a[1] ist int&
    const Array ca(10);
    ca[1] = 2; // Fehler: der Typ von ca[1] ist int
}

Memberfunktionen mit Ref-Qualifier

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

  • kein Ref-Qualifier: Der implizite Objektparameter hat den Typ Lvalue-Referenz auf CV-qualifiziertes X und darf zusätzlich Rvalue-implizierte Objektargumente binden
  • Lvalue-Ref-Qualifier: Der implizite Objektparameter hat den Typ Lvalue-Referenz auf CV-qualifiziertes X
  • Rvalue-Ref-Qualifier: 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 bleibt * this ein Lvalue-Ausdruck.

(seit C++11)

Virtuelle und rein virtuelle Funktionen

Eine nicht-statische Memberfunktion kann als virtual oder pure virtual deklariert werden. Weitere Details finden Sie unter virtual functions und abstract classes .

Explizite Objekt-Memberfunktionen

Für eine nicht-statische, nicht-virtuelle Memberfunktion, die nicht mit CV-Qualifizierer oder Ref-Qualifizierer deklariert wurde, kann ihr erster Parameter, sofern es sich nicht um ein Funktionsparameter-Paket handelt, ein expliziter Objektparameter sein (gekennzeichnet durch das vorangestellte 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 Memberfunktions-Templates ermöglicht der explizite Objektparameter die Deduktion von Typ und Wertkategorie. Diese Sprachfunktion wird „Deduzieren von this “ genannt:

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 ermöglicht die Deduplizierung von const- und nicht-const-Memberfunktionen. Siehe Array-Subscript-Operator für ein Beispiel.

Innerhalb des Rumpfes 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 Zeiger auf Member:

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)

Spezielle Elementfunktionen

Einige Memberfunktionen sind speziell : unter bestimmten Umständen werden sie vom Compiler definiert, selbst wenn sie nicht vom Benutzer definiert wurden. Sie sind:

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

Spezielle Elementfunktionen zusammen mit den Vergleichsoperatoren (seit C++20) sind die einzigen Funktionen, die standardmäßig definiert werden können, das heißt, definiert mit = default anstelle des Funktionsrumpfs (siehe deren Seiten für Details).

Hinweise

Feature-Test-Makro Wert Std Feature
__cpp_ref_qualifiers 200710L (C++11) Ref-Qualifier
__cpp_explicit_this_parameter 202110L (C++23) Expliziter Objektparameter ( Ableitung von this )

Beispiel

#include <exception>
#include <iostream>
#include <string>
#include <utility>
struct S
{
    int data;
    // einfacher konvertierender Konstruktor (Deklaration)
    S(int val);
    // einfacher expliziter Konstruktor (Deklaration)
    explicit S(std::string str);
    // konstante Memberfunktion (Definition)
    virtual int getData() const { return data; }
};
// Definition des Konstruktors
S::S(int val) : data(val)
{
    std::cout << "ctor1 called, data = " << data << '\n';
}
// dieser Konstruktor hat eine Catch-Klausel
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; // Catch-Klausel des Konstruktors sollte immer erneut werfen
}
struct D : S
{
    int data2;
    // Konstruktor mit einem Standardargument
    D(int v1, int v2 = 11) : S(v1), data2(v2) {}
    // virtuelle Memberfunktion
    int getData() const override { return data * data2; }
    // Nur-Lvalue-Zuweisungsoperator
    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: Zuweisung an Lvalue
//  D(5) = d1; // FEHLER: keine passende Überladung von operator=
}

Ausgabe:

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

Fehlerberichte

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

DR Angewendet auf Verhalten wie veröffentlicht Korrektes Verhalten
CWG 194 C++98 unklar, ob eine nicht-statische Memberfunktion
denselben Namen wie der umschließende Klassenname haben konnte
explizite Namenseinschränkung hinzugefügt

Siehe auch