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

Une fonction membre non statique est une fonction déclarée dans une spécification de membre d'une classe sans les spécificateurs static ou friend (voir fonctions membres statiques et déclaration friend pour l'effet de ces mots-clés).

class S
{
    int mf1(); // déclaration de fonction membre non statique
    void mf2() volatile, mf3() &&; // peut avoir des qualificateurs cv et/ou un qualificateur de référence
        // la déclaration ci-dessus est équivalente à deux déclarations séparées :
        // void mf2() volatile;
        // void mf3() &&;
    int mf4() const { return data; } // peut être définie en ligne
    virtual void mf5() final; // peut être virtuelle, peut utiliser final/override
    S() : data(12) {} // les constructeurs sont aussi des fonctions membres
    int data;
};
int S::mf1() { return 7; } // si non définie en ligne, doit être définie au niveau du namespace

Constructeurs , destructeurs , et fonctions de conversion utilisent des syntaxes spéciales pour leurs déclarations. Les règles décrites dans cette page peuvent ne pas s'appliquer à ces fonctions. Consultez leurs pages respectives pour plus de détails.

Une fonction membre à objet explicite est une fonction membre non statique avec un paramètre objet explicite .

(depuis C++23)

Une fonction membre d'objet implicite est une fonction membre non statique sans paramètre d'objet explicite (avant C++23, c'était le seul type de fonction membre non statique, et donc désignée comme « fonction membre non statique » dans la littérature).

Table des matières

Explication

Toute déclaration de fonction est autorisée, avec des éléments syntaxiques supplémentaires qui sont uniquement disponibles pour les fonctions membres non statiques : spécificateurs purs , qualificateurs cv , qualificateurs de référence, final et override spécificateurs (depuis C++11) , et listes d'initialisation de membres .

Une fonction membre non statique de la classe X peut être appelée

1) Pour un objet de type X en utilisant l'opérateur d'accès aux membres de classe
2) Pour un objet d'une classe dérivée de X
3) Directement depuis le corps d'une fonction membre de X
4) Directement depuis le corps d'une fonction membre d'une classe dérivée de X

Appeler une fonction membre non statique de la classe X sur un objet qui n'est pas de type X , ou d'un type dérivé de X provoque un comportement indéfini.

Dans le corps d'une fonction membre non statique de X , toute expression d'identifiant e (par exemple un identifiant) qui se résout en un membre non-type non statique de X ou d'une classe de base de X , est transformée en une expression d'accès membre ( * this ) . e (à moins qu'elle ne fasse déjà partie d'une expression d'accès membre). Cela ne se produit pas dans le contexte de définition de template, donc un nom peut devoir être préfixé par this - > explicitement pour devenir dépendant .

struct S
{
    int n;
    void f();
};
void S::f()
{
    n = 1; // transformé en (*this).n = 1;
}
int main()
{
    S s1, s2;
    s1.f(); // modifie s1.n
}

Dans le corps d'une fonction membre non statique de X , tout unqualified-id qui se résout en un membre statique, un énumérateur ou un type imbriqué de X ou d'une classe de base de X , est transformé en le qualified-id correspondant :

struct S
{
    static int n;
    void f();
};
void S::f()
{
    n = 1; // transformé en S::n = 1;
}
int main()
{
    S s1, s2;
    s1.f(); // modifie S::n
}

Fonctions membres avec qualificateurs cv

Une fonction membre d'objet implicite peut être déclarée avec une séquence de qualificatifs cv ( const , volatile , ou une combinaison de const et volatile ), cette séquence apparaît après la liste des paramètres dans la déclaration de fonction . Les fonctions avec différentes séquences de qualificatifs cv (ou sans séquence) ont des types différents et peuvent donc se surcharger mutuellement.

Dans le corps d'une fonction avec une séquence de qualificatifs cv, * this est qualifié cv, par exemple dans une fonction membre avec le qualificatif const , seules les autres fonctions membres avec le qualificatif const peuvent être appelées normalement. Une fonction membre sans le qualificatif const peut toujours être appelée si const_cast est appliqué ou via un chemin d'accès qui n'implique pas this .

#include <vector>
struct Array
{
    std::vector<int> data;
    Array(int sz) : data(sz) {}
    // fonction membre const
    int operator[](int idx) const
    {                     // le pointeur this a le type const Array*
        return data[idx]; // transformé en (*this).data[idx];
    }
    // fonction membre non-const
    int& operator[](int idx)
    {                     // le pointeur this a le type Array*
        return data[idx]; // transformé en (*this).data[idx]
    }
};
int main()
{
    Array a(10);
    a[1] = 1;  // OK : le type de a[1] est int&
    const Array ca(10);
    ca[1] = 2; // Erreur : le type de ca[1] est int
}

Fonctions membres avec ref-qualifier

Une fonction membre d'objet implicite peut être déclarée sans ref-qualifier, avec un ref-qualifier lvalue (le token & après la liste de paramètres) ou le ref-qualifier rvalue (le token && après la liste de paramètres). Pendant la résolution de surcharge , une fonction membre d'objet implicite avec une séquence de cv-qualification de classe X est traitée comme suit :

  • sans ref-qualifier : le paramètre objet implicite a le type référence lvalue vers X qualifié cv et est autorisé à lier un argument objet implicite rvalue
  • ref-qualifier lvalue : le paramètre objet implicite a le type référence lvalue vers X qualifié cv
  • ref-qualifier rvalue : le paramètre objet implicite a le type référence rvalue vers X qualifié cv
#include <iostream>
struct S
{
    void f() &  { std::cout << "lvalue\n"; }
    void f() && { std::cout << "rvalue\n"; }
};
int main()
{
    S s;
    s.f();            // affiche "lvalue"
    std::move(s).f(); // affiche "rvalue"
    S().f();          // affiche "rvalue"
}

Remarque : contrairement à la cv-qualification, la ref-qualification ne modifie pas les propriétés du pointeur this : dans une fonction avec ref-qualifier rvalue, * this reste une expression lvalue.

(depuis C++11)

Fonctions virtuelles et fonctions virtuelles pures

Une fonction membre non statique peut être déclarée virtual ou pure virtual . Voir virtual functions et abstract classes pour plus de détails.

Fonctions membres à objet explicite

Pour une fonction membre non statique non virtuelle non déclarée avec un qualificateur cv ou un qualificateur de référence, son premier paramètre, s'il ne s'agit pas d'un pack de paramètres de fonction , peut être un paramètre objet explicite (désigné par le mot-clé préfixé 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”
};

Pour les modèles de fonctions membres, le paramètre objet explicite permet la déduction du type et de la catégorie de valeur, cette fonctionnalité du langage est appelée « déduction de this » :

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&
}

Cela permet de dédupliquer les fonctions membres const et non const, voir opérateur d'indice de tableau pour un exemple.

À l'intérieur du corps d'une fonction membre à objet explicite, le pointeur this ne peut pas être utilisé : tous les accès aux membres doivent être effectués via le premier paramètre, comme dans les fonctions membres statiques :

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

Un pointeur vers une fonction membre à objet explicite est un pointeur ordinaire vers une fonction, et non un pointeur vers membre :

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
(depuis C++23)

Fonctions membres spéciales

Certaines fonctions membres sont spéciales : dans certaines circonstances, elles sont définies par le compilateur même si elles ne sont pas définies par l'utilisateur. Elles sont :

(depuis C++11)
(depuis C++11)

Fonctions membres spéciales ainsi que les opérateurs de comparaison (depuis C++20) sont les seules fonctions qui peuvent être définies par défaut , c'est-à-dire définies en utilisant = default au lieu du corps de fonction (voir leurs pages pour plus de détails).

Notes

Macro de test de fonctionnalité Valeur Std Fonctionnalité
__cpp_ref_qualifiers 200710L (C++11) ref-qualifiers
__cpp_explicit_this_parameter 202110L (C++23) paramètre objet explicite ( déduction de this )

Exemple

#include <exception>
#include <iostream>
#include <string>
#include <utility>
struct S
{
    int data;
    // constructeur de conversion simple (déclaration)
    S(int val);
    // constructeur explicite simple (déclaration)
    explicit S(std::string str);
    // fonction membre const (définition)
    virtual int getData() const { return data; }
};
// définition du constructeur
S::S(int val) : data(val)
{
    std::cout << "ctor1 appelé, data = " << data << '\n';
}
// ce constructeur a une clause catch
S::S(std::string str) try : data(std::stoi(str))
{
    std::cout << "ctor2 appelé, data = " << data << '\n';
}
catch(const std::exception&)
{
    std::cout << "ctor2 échoué, la chaîne était '" << str << "'\n";
    throw; // la clause catch du constructeur doit toujours relancer
}
struct D : S
{
    int data2;
    // constructeur avec un argument par défaut
    D(int v1, int v2 = 11) : S(v1), data2(v2) {}
    // fonction membre virtuelle
    int getData() const override { return data * data2; }
    // opérateur d'affectation uniquement pour lvalues
    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 : affectation à une lvalue
//  D(5) = d1; // ERREUR : aucune surcharge appropriée de operator=
}

Sortie :

ctor1 appelé, data = 1
ctor2 appelé, data = 2
ctor2 échoué, la chaîne était 'not a number'
2
ctor1 appelé, data = 3

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR S'applique à Comportement publié Comportement corrigé
CWG 194 C++98 ambiguïté quant à savoir si une fonction membre non statique
pouvait avoir le même nom que celui de la classe englobante
restriction de dénomination explicite ajoutée

Voir aussi