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
long
et si le programme appelant fournit un argument réel de typeint
, l’argument réel est promu à l’aide d’une conversion de type standard en typelong
(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 typedouble
avant l’appel de fonction.Tout
signed char
type énuméré ouunsigned char
,signed short
ouunsigned short
champ bit est converti en un ou un à l’aide d’unesigned int
unsigned 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.