Expressões pós-fixadas

As expressões pós-fixadas consistem em expressões primárias ou expressões nas quais operadores pós-fixados seguem uma expressão primária. Os operadores pós-fixados estão listados na tabela a seguir.

Operadores pós-fixados

Nome do operador Notação do operador
Operador de subscrito [ ]
Operador de chamada de função ( )
Operador de conversão de tipo explícito nome de tipo( )
Operador de acesso de membro . ou ->
Operador de incremento Postfix ++
Operador de decremento Postfix --

A sintaxe a seguir descreve expressões pós-fixadas possíveis:

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 )

A expressão pós-fixada acima poderá ser uma expressão primária ou outra expressão pós-fixada. As expressões pós-fixadas são agrupadas da esquerda para a direita; com isso, elas podem ser encadeadas da seguinte forma:

func(1)->GetValue()++

Na expressão acima, func é uma expressão primária, func(1) é uma expressão pós-fixada de função, func(1)->GetValue é uma expressão pós-fixada que especifica um membro da classe, func(1)->GetValue() é outra expressão pós-fixada de função e a expressão inteira é uma expressão pós-fixada que incrementa o valor retornado de GetValue. O significado da expressão, no conjunto, é "função de chamada passando 1 como um argumento e obtendo um ponteiro para uma classe como um valor de retorno". Em seguida, chame GetValue() nessa classe e incremente o valor retornado.

As expressões listadas acima são expressões de atribuição, ou seja, o resultado dessas expressões deve ser um r-value.

O formato de expressão pós-fixada

simple-type-name ( expression-list )

indica a invocação do construtor. Caso simple-type-name seja um tipo fundamental, a lista de expressões deve ser formada por uma única expressão, a qual indica uma conversão do valor da expressão no tipo fundamental. Esse tipo de expressão convertida imita um construtor. Como esse formato permite que classes e tipos fundamentais sejam construídos usando a mesma sintaxe, ele é especialmente útil na definição de classes de modelo.

A palavra-chave cast é dynamic_cast, static_cast ou reinterpret_cast. Mais informações podem ser encontradas em dynamic_cast, static_cast e reinterpet_cast.

O operador typeid é considerado uma expressão pós-fixada. Consulte operador de typeid.

Argumentos formais e reais

Programas de chamada passam as informações para funções chamadas em "argumentos reais". As funções chamadas acessam as informações usando os "argumentos formais" correspondentes.

Quando uma função for chamada, as seguintes tarefas serão executadas:

  • Todos os argumentos reais (aqueles fornecidos pelo chamador) são avaliados. Não há nenhuma ordem implícita na qual esses argumentos são avaliados, mas todos os argumentos são avaliados e todos os efeitos colaterais são concluídos antes da entrada na função.

  • Cada argumento formal é inicializado com seu argumento correspondente na lista de expressões. (Um argumento formal é um argumento declarado no cabeçalho da função e utilizado no corpo de uma função.). As conversões são feitas como por inicialização: ambas as conversões padrão e as definidas pelo usuário são executadas na conversão de um argumento real para o tipo correto. A inicialização executada é ilustrada de modo conceitual pelo seguinte código:

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

    As inicializações conceituais antes da chamada são:

    int Temp_i = 7;
    Func( Temp_i );
    

    A inicialização é executada como se estivesse usando a sintaxe de sinal de igualdade em vez de sintaxe de parênteses. Uma cópia de i é feita antes de transmitir o valor à função. (Para obter mais informações, consulte Inicializadores e Conversões).

    Portanto, se o protótipo de função (declaração) chamar um argumento do tipolong, e se o programa de chamada fornecer um argumento real do tipo int, o argumento real será promovido usando uma conversão de tipo padrão para o tipo long (consulte Conversões padrão).

    É um erro fornecer um argumento real para o qual não há conversão padrão ou definida pelo usuário para o tipo de argumento formal.

    Para argumentos reais de tipos de classe, o argumento formal é inicializado chamando o construtor da classe. (Consulte Construtores para obter mais informações sobre essas funções de membro de classe especiais.)

  • A chamada de função é executada.

O seguinte fragmento de programa demonstra uma chamada de função:

// 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 é chamado do principal, o parâmetro formal param1 inicializa com o valor de i (i é convertido para o tipo long para corresponder ao tipo correto usando uma conversão padrão), e o parâmetro formal param2 inicializa com o valor de j (j é convertido para o tipo double usando uma conversão padrão).

Tratamento de tipos de argumento

Os argumentos formais declarados como tipos const não podem ser alterados no corpo de uma função. As funções podem alterar qualquer argumento que não seja do tipo const. No entanto, a alteração é local para a função e não afetará o valor do argumento real, a menos que o argumento real seja uma referência a um objeto que não seja do tipo const.

As seguintes funções ilustram alguns desses conceitos:

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

Reticências e argumentos padrão

As funções podem ser declaradas para aceitar menos argumentos do que o especificado na definição da função, usando um de dois métodos: reticências (...) ou argumentos padrão.

As reticências indicam que os argumentos podem ser necessários, mas que o número e os tipos não são especificados na declaração. Essa geralmente é uma prática inadequada de programação do C++ porque ela elimina um dos benefícios de segurança do tipo C++:. Diferentes conversões são aplicadas às funções declaradas com reticências do que nas funções para as quais os tipos de argumentos formais e reais são conhecidos:

  • Se o argumento real for do tipo float, ele será promovido para o tipo double antes da chamada da função.

  • Qualquer signed char ou unsigned char, signed short ou unsigned short, tipo enumerado, ou campo de bits é convertido para um signed int ou um unsigned int usando promoção integral.

  • Qualquer argumento de tipo de classe é passado por valor como estrutura de dados; a cópia é criada por cópia binário em vez de chamar o construtor de cópia de classe (se houver).

As reticências, se utilizadas, deverão ser declaradas por último na lista de argumentos. Para obter mais informações sobre como passar um número variável de argumentos, consulte os tópicos sobre va_arg, va_start e va_list na Referência de biblioteca de runtime.

Para obter mais informações sobre os argumentos padrão na programação CLR, consulte Listas de argumentos variáveis (...) (C++/CLI).

Os argumentos padrão permitem que você especifique o valor que um argumento deverá assumir caso nenhum seja fornecido na chamada de função. O fragmento de código a seguir mostra como os argumentos padrão funcionam. Para obter mais informações sobre as restrições na especificação de argumentos padrão, consulte Argumentos padrão.

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

O programa anterior declara uma função, print, que usa dois argumentos. No entanto, o segundo argumento, terminador, tem um valor padrão, "\n". Em main, s duas primeiras chamadas para print permitem que o segundo argumento padrão forneça uma nova linha para encerrar a cadeia de caracteres impressa. A terceira chamada especifica um valor explícito para o segundo argumento. A saída do programa é

hello,
world!
good morning, sunshine.

Confira também

Tipos de expressões