Expressions suffixées

Les expressions suffixées se composent d'expressions primaires ou d'expressions dans lesquelles les opérateurs suffixés suivent une expression primaire. Les opérateurs suffixés sont répertoriées dans le tableau suivant.

Opérateurs suffixés

Nom de l’opérateur Notation de l'opérateur
Opérateur Indice [ ]
Opérateur d'appel de fonction ( )
Opérateur de conversion de type explicite type-name( )
Opérateur d’accès aux membres . ou ->
Opérateur d'incrément suffixé ++
Opérateur de décrémentation suffixé --

La syntaxe suivante décrit les expressions suffixées possibles :

primary-expression
postfix-expression[expression]postfix-expression(expression-list)simple-type-name(expression-list)postfix-expression.namepostfix-expression->namepostfix-expression++postfix-expression--cast-keyword < typename > (expression )typeid ( typename )

La postfix-expression ci-dessus peut être une expression primaire ou une autre expression de postfix. Les expressions suffixées sont regroupées de gauche à droite. Elles peuvent ainsi être chaînées les unes aux autres comme suit :

func(1)->GetValue()++

Dans l’expression ci-dessus, func est une expression primaire, func(1) est une expression postfixe de fonction, func(1)->GetValue est une expression de postfix spécifiant un membre de la classe, func(1)->GetValue() est une autre expression postfix de fonction, et l’expression entière est une expression postfix qui incrémente la valeur de retour de GetValue. L’expression entière signifie : Appeler fonction passant 1 comme argument et obtenir un pointeur vers une classe comme valeur de retour. Appelez GetValue() ensuite cette classe, puis incrémentez la valeur retournée.

Les expressions répertoriées ci-dessus sont des expressions d'assignation, ce qui signifie que le résultat de ces expressions doit être une r-value.

Forme de l'expression suffixée

simple-type-name ( expression-list )

indique l'appel du constructeur. Si le nom-type-simple est un type fondamental, la liste d'expressions doit être une expression unique, et cette expression montre un cast de la valeur de l'expression au type fondamental. Ce type d'expression de cast simule un constructeur. Cette forme permet aux classes et aux types fondamentaux d'être construits à l'aide de la même syntaxe. Elle est donc particulièrement utile lorsque vous définissez des classes de modèles.

Le cast-keyword est l’un des dynamic_cast, static_cast ou reinterpret_cast. Vous trouverez plus d’informations dans dynamic_cast, static_cast et reinterpet_cast.

L’opérateur typeid est considéré comme une expression postfixée. Consultez l’opérateur typeid.

Arguments formels et arguments réels

L’appel de programmes transmet des informations aux fonctions appelées dans les « arguments réels ». Les fonctions appelées accèdent aux informations à l’aide des « arguments formels » correspondants.

Lorsqu’une fonction est appelée, les tâches suivantes sont effectuées :

  • Tous les arguments réels (ceux fournis par l'appelant) sont évalués. Il n’y a pas d’ordre implicite dans lequel ces arguments sont évalués, mais ils sont tous évalués et les effets secondaires sont résolus avant l’entrée dans la fonction.

  • Chaque argument formel est initialisé avec son argument réel correspondant dans la liste d'expressions. (Un argument formel est un argument déclaré dans l’en-tête de fonction et utilisé dans le corps d’une fonction.) Les conversions sont effectuées comme si par initialisation : les conversions standard et définies par l’utilisateur sont effectuées lors de la conversion d’un argument réel en type correct. L'initialisation exécutée est illustrée conceptuellement par le code suivant :

    void Func( int i ); // Function prototype
    ...
    Func( 7 );          // Execute function call
    

    Les initialisations conceptuelles avant l'appel sont :

    int Temp_i = 7;
    Func( Temp_i );
    

    Notez que l'initialisation est exécutée comme si la syntaxe de signe égal était utilisée au lieu de la syntaxe de parenthèses. Une copie de i est effectuée avant de passer la valeur à la fonction. (Pour plus d’informations, consultez Initialiseurs et conversions).

    Par conséquent, si le prototype de fonction (déclaration) appelle un argument de type longet si le programme appelant fournit un argument réel de type int, l’argument réel est promu à l’aide d’une conversion de type standard en type long (voir Conversions standard).

    C’est une erreur de fournir un argument réel pour lequel il n’existe aucune conversion standard ou définie par l’utilisateur au type de l’argument formel.

    Pour les arguments réels du type classe, l’argument formel est initialisé en appelant le constructeur de la classe. (Pour plus d’informations sur ces fonctions membres de classe spéciales, consultez Constructeurs .)

  • L'appel de fonction est exécuté.

Le fragment de programme suivant montre un appel de fonction :

// expre_Formal_and_Actual_Arguments.cpp
void func( long param1, double param2 );

int main()
{
    long i = 1;
    double j = 2;

    // Call func with actual arguments i and j.
    func( i, j );
}

// Define func with formal parameters param1 and param2.
void func( long param1, double param2 )
{
}

Quand func est appelé à partir de main, le paramètre param1 formel est initialisé avec la valeur de i (i est converti en type long pour correspondre au type correct à l’aide d’une conversion standard) et le paramètre param2 formel est initialisé avec la valeur de j (j est converti en type double à l’aide d’une conversion standard).

Traitement des types d'arguments

Les arguments formels déclarés en tant que const types ne peuvent pas être modifiés dans le corps d’une fonction. Les fonctions peuvent modifier n’importe quel argument qui n’est pas de type const. Toutefois, la modification est locale à la fonction et n’affecte pas la valeur de l’argument réel, sauf si l’argument réel était une référence à un objet non de type const.

Les fonctions suivantes illustrent certains de ces concepts :

// expre_Treatment_of_Argument_Types.cpp
int func1( const int i, int j, char *c ) {
   i = 7;   // C3892 i is const.
   j = i;   // value of j is lost at return
   *c = 'a' + j;   // changes value of c in calling function
   return i;
}

double& func2( double& d, const char *c ) {
   d = 14.387;   // changes value of d in calling function.
   *c = 'a';   // C3892 c is a pointer to a const object.
    return d;
}

Points de suspension et arguments par défaut

Les fonctions peuvent être déclarées pour accepter moins d’arguments que le nombre spécifié dans la définition de fonction, en utilisant l’une des deux méthodes suivantes : points de suspension (...) ou arguments par défaut.

Les points de suspension indiquent que des arguments peuvent être requis, mais que le nombre et les types ne sont pas spécifiés dans la déclaration. C'est habituellement une mauvaise pratique de programmation C++ car elle occulte l'un des avantages du C++ : la sécurité de type. Différentes conversions sont appliquées aux fonctions déclarées avec des points de suspension par rapport aux fonctions pour lesquelles les types d’arguments formels et réels sont connus :

  • Si l’argument réel est de type float, il est promu en type double avant l’appel de fonction.

  • Tout signed char type énuméré ou unsigned char, signed short ou unsigned shortchamp bit est converti en un ou un à l’aide d’une signed intunsigned int promotion intégrale.

  • Tout argument de type classe est transmis par valeur comme une structure de données. La copie est créée par copie binaire plutôt que par appel d’un constructeur de copie de la classe (le cas échéant).

Les points de suspension, s’ils sont utilisés, doivent être déclarés en dernier dans la liste d’arguments. Pour plus d’informations sur la transmission d’un nombre variable d’arguments, consultez la discussion sur les va_arg, les va_start et les va_list dans la référence de la bibliothèque d’exécution.

Pour plus d’informations sur les arguments par défaut dans la programmation CLR, consultez Listes d’arguments variables (...) (C++/CLI).

Les arguments par défaut vous permettent de spécifier la valeur qu’un argument doit prendre si aucune n’est fournie dans l’appel de fonction. Le fragment de code suivant montre le fonctionnement des arguments par défaut. Pour plus d’informations sur les restrictions relatives à la spécification des arguments par défaut, consultez Arguments par défaut.

// expre_Ellipsis_and_Default_Arguments.cpp
// compile with: /EHsc
#include <iostream>

// Declare the function print that prints a string,
// then a terminator.
void print( const char *string,
            const char *terminator = "\n" );

int main()
{
    print( "hello," );
    print( "world!" );

    print( "good morning", ", " );
    print( "sunshine." );
}

using namespace std;
// Define print.
void print( const char *string, const char *terminator )
{
    if( string != NULL )
        cout << string;

    if( terminator != NULL )
        cout << terminator;
}

Le programme précédent déclare une fonction, print, qui accepte deux arguments. Toutefois, le deuxième argument, terminateur, a une valeur par défaut, "\n". Dans main, les deux premiers appels permettent au print deuxième argument par défaut de fournir une nouvelle ligne pour terminer la chaîne imprimée. Le troisième appel indique une valeur explicite pour le deuxième argument. Le résultat généré par le programme est

hello,
world!
good morning, sunshine.

Voir aussi

Types d’expressions