Espressioni in forma suffissa

Le espressioni di suffisso sono costituite da espressioni primarie o da espressioni in cui gli operatori di suffisso seguono un'espressione primaria. Nella tabella riportata di seguito vengono elencati gli operatori di suffisso.

Operatori di suffisso

Nome operatore Notazione dell'operatore
Operatore indice secondario [ ]
Operatore di chiamata di funzione ( )
Operatore esplicito di conversione dei tipi type-name( )
Operatore di accesso ai membri . o ->
Operatore di incremento suffisso ++
Operatore decrement postfix --

Nella sintassi seguente vengono descritte le possibili espressioni di suffisso:

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 )

L'espressione postfix precedente può essere un'espressioneprimaria o un'altra espressione di prefisso. Le espressioni di suffisso vengono raggruppate da sinistra a destra, consentendone il concatenamento nel modo seguente:

func(1)->GetValue()++

Nell'espressione precedente, func è un'espressione primaria, func(1) è un'espressione di prefisso di funzione, func(1)->GetValue è un'espressione di prefisso che specifica un membro della classe, func(1)->GetValue() è un'altra espressione di prefisso di funzione e l'intera espressione è un'espressione di prefisso che incrementa il valore restituito di GetValue. Il significato dell'intera espressione è "chiamare func passando 1 come argomento e ottenere un puntatore a una classe come valore restituito. Chiamare GetValue() quindi su tale classe, quindi incrementare il valore restituito.

Le espressioni sopra elencate sono espressioni di assegnazione, pertanto il loro risultato deve essere un r-value.

Il formato dell'espressione di suffisso

simple-type-name ( expression-list )

indica la chiamata del costruttore. Se il nome di tipo semplice è un tipo fondamentale, l'elenco di espressioni deve essere costituito da un'unica espressione, la quale indica un cast del valore dell'espressione al tipo fondamentale. Questo tipo di espressione cast riproduce un costruttore. Poiché questo formato consente la costruzione dei tipi fondamentali e delle classi utilizzando la stessa sintassi, è particolarmente utile quando si definiscono le classi modello.

La parola chiave cast è una di dynamic_casto static_castreinterpret_cast. Altre informazioni sono disponibili in dynamic_caststatic_cast e reinterpet_cast.

L'operatore typeid è considerato un'espressione di prefisso. Vedere l'operatore typeid.

Argomenti formali ed effettivi

I programmi chiamanti passano informazioni alle funzioni chiamate in "argomenti effettivi". Le funzioni chiamate accedono alle informazioni usando gli "argomenti formali" corrispondenti.

Quando viene chiamata una funzione, vengono eseguite le seguenti attività:

  • Tutti gli argomenti effettivi forniti dal chiamante vengono valutati. Non esiste un ordine implicito di valutazione degli argomenti, ma ognuno di essi viene valutato, e i relativi effetti collaterali vengono completati, prima di essere inseriti nella funzione.

  • Ogni argomento formale viene inizializzato con il corrispondente argomento effettivo presente nell'elenco di espressioni. Un argomento formale è un argomento dichiarato nell'intestazione della funzione e usato nel corpo di una funzione. Le conversioni vengono eseguite come se fosse l'inizializzazione. Le conversioni standard e definite dall'utente vengono eseguite per convertire un argomento effettivo nel tipo corretto. Il seguente codice illustra a livello concettuale l'inizializzazione che viene eseguita:

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

    Le inizializzazioni concettuali precedenti alla chiamata sono:

    int Temp_i = 7;
    Func( Temp_i );
    

    Si noti che l'inizializzazione viene eseguita come se si utilizzasse la sintassi del segno di uguale, anziché la sintassi di parentesi. Prima di passare il valore alla funzione, viene effettuata una copia di i. Per altre informazioni, vedere Inizializzatori e conversioni).

    Pertanto, se il prototipo di funzione (dichiarazione) chiama per un argomento di tipo longe se il programma chiamante fornisce un argomento effettivo di tipo int, l'argomento effettivo viene alzato di livello usando una conversione di tipo standard nel tipo long (vedere Conversioni standard).

    Fornire un argomento effettivo per il quale non esistono conversioni standard o definite dall'utente al tipo dell'argomento formale costituisce un errore.

    Nel caso degli argomenti effettivi di tipo classe, l'argomento formale viene inizializzato chiamando il costruttore della classe. (Vedere Costruttori per altre informazioni su queste funzioni membro di classe speciali.

  • Viene eseguita la chiamata di funzione.

Il seguente frammento di programma illustra una chiamata di funzione:

// 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 )
{
}

Quando func viene chiamato da main, il parametro param1 formale viene inizializzato con il valore di i (i viene convertito in tipo in modo che corrisponda al tipo corretto usando una conversione standard) e il parametro param2 formale viene inizializzato con il valore di j (j viene convertito in tipo longdouble utilizzando una conversione standard).

Trattamento dei tipi di argomento

Gli argomenti formali dichiarati come const tipi non possono essere modificati all'interno del corpo di una funzione. Le funzioni possono modificare qualsiasi argomento non di tipo const. Tuttavia, la modifica è locale per la funzione e non influisce sul valore dell'argomento effettivo, a meno che l'argomento effettivo non sia un riferimento a un oggetto di tipo const.

Nelle funzioni seguenti vengono illustrati alcuni di questi concetti:

// 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;
}

Puntini di sospensione e argomenti predefiniti

Le funzioni possono essere dichiarate per accettare un numero di argomenti minore rispetto a quello specificato nella definizione di funzione, mediante uno dei due metodi: puntini di sospensione (...) o argomenti predefiniti.

I puntini di sospensione indicano che gli argomenti possono essere necessari, ma che il numero e i tipi non sono specificati nella dichiarazione. Si tratta in genere di una procedura di programmazione C++ di basso livello perché vanifica uno dei vantaggi di C++, l'indipendenza dai tipi. Le conversioni diverse vengono applicate alle funzioni dichiarate con puntini di sospensione rispetto a quelle per le quali sono noti i tipi di argomento formali e effettivi:

  • Se l'argomento effettivo è di tipo float, viene alzato di livello al tipo double prima della chiamata di funzione.

  • Qualsiasi signed char campo di tipo o unsigned charsigned short , o unsigned short, enumerato o bit viene convertito in un signed int oggetto o in un oggetto che usa l'innalzamento unsigned int di livello integrale.

  • Qualsiasi argomento di tipo classe viene passato in base al valore come struttura di dati; la copia viene creata tramite la copia binaria anziché richiamando il costruttore di copia della classe (se presente).

I puntini di sospensione, se usati, devono essere dichiarati per ultimo nell'elenco di argomenti. Per altre informazioni sul passaggio di un numero variabile di argomenti, vedere la discussione su va_arg, va_start e va_list nella guida di riferimento alla libreria di runtime.

Per informazioni sugli argomenti predefiniti nella programmazione CLR, vedere Elenchi di argomenti variabili (...) (C++/CLI).

Gli argomenti predefiniti consentono di specificare il valore che deve assumere un argomento se non viene fornito nella chiamata di funzione. Nel frammento di codice seguente viene illustrato come usare gli argomenti predefiniti. Per altre informazioni sulle restrizioni relative all'impostazione degli argomenti predefiniti, vedere Argomenti predefiniti.

// 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;
}

Nel programma precedente viene dichiarata una funzione, print, che accetta due argomenti. Tuttavia, il secondo argomento, terminatore, ha un valore predefinito, "\n". In mainle prime due chiamate consentono al print secondo argomento predefinito di fornire una nuova riga per terminare la stringa stampata. La terza chiamata specifica un valore esplicito per il secondo argomento. L'output del programma è

hello,
world!
good morning, sunshine.

Vedi anche

Tipi di espressioni