Udostępnij przez


Wyrażenia przyrostków

Wyrażenia przyrostkowe składają się z podstawowego wyrażenia lub wyrażeń, w których operatory przyrostkowe następują po wyrażeniu podstawowym. Operatory przyrostkowe są wymienione w poniższej tabeli.

Operatory przyrostka

Nazwa operatora Notacja operatora
Operator indeksu dolnego [ ]
Operator wywołania funkcji ( )
Operator konwersji jawnego typu type-name( )
Operator dostępu do składowych . lub ->
Operator przyrostka przyrostkowego ++
Operator dekrementacji postfiksu --

Następująca składnia opisuje możliwe wyrażenia przyrostkowe:

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 )

Powyższe wyrażenie-postfix-może być wyrażeniem podstawowym lub innym wyrażeniem postfiksu. Grupa wyrażeń przyrostkowych od lewej do prawej, umożliwia w ten sposób łączenie wyrażeń w następujący sposób:

func(1)->GetValue()++

W powyższym wyrażeniu func jest wyrażeniem podstawowym, func(1) jest wyrażeniem postfiksu funkcji, func(1)->GetValue jest wyrażeniem postfiksu określającym składową klasy, func(1)->GetValue() jest innym wyrażeniem postfiksu funkcji, a całe wyrażenie jest wyrażeniem postfiksu zwiększającym zwracaną wartość GetValue. Znaczenie wyrażenia jako całości to „wywołaj funkcję przekazywania 1 jako argument i uzyskaj wskaźnik do klasy jako wartość zwracaną. Następnie wywołaj metodę GetValue() dla tej klasy, a następnie zwiększ zwróconą wartość.

Wyrażenia wymienione powyżej są wyrażeniami przypisania, co oznacza, że wyniki wyrażenia muszą być r-wartościami.

Forma wyrażenia przyrostkowego

simple-type-name ( expression-list )

wskazuje wywołanie konstruktora. Jeśli simple-type-name jest typem podstawowym, lista wyrażeń musi być wyrażeniem pojedynczym, a to wyrażenie wskazuje rzutowanie wartości wyrażenia na typ podstawowy. Ten typ wyrażenia rzutującego naśladuje konstruktor. Jako że ta forma umożliwia konstruowanie podstawowych typów i klas przy użyciu tej samej składni, ta forma jest szczególnie przydatna podczas definiowania klas szablonów.

Słowo kluczowe cast-keyword jest jednym z dynamic_castelementów , static_cast lub reinterpret_cast. Więcej informacji można znaleźć w temacie dynamic_cast, static_cast i reinterpet_cast.

Operator typeid jest uważany za wyrażenie postfiksu. Zobacz operator typeid.

Argumenty formalne i rzeczywiste

Wywoływanie programów przekazuje informacje do wywoływanych funkcji w "rzeczywistych argumentach". Wywoływane funkcje uzyskują dostęp do informacji przy użyciu odpowiednich "formalnych argumentów".

Po wywołaniu funkcji, wykonywane są następujące zadania:

  • Wszystkie rzeczywiste argumenty (dostarczane przez wywołującego) są obliczane. Nie ma niejawnego porządku, w którym argumenty są obliczane, ale wszystkie argumenty są obliczone i wszystkie efekty uboczne zakończone przed wejściem do funkcji.

  • Każdy argument formalny jest inicjowany z odpowiadającym mu argumentem rzeczywistym na liście wyrażeń. (Argument formalny jest argumentem zadeklarowanym w nagłówku funkcji i używanym w treści funkcji). Konwersje są wykonywane tak, jakby inicjalizacja — zarówno konwersje standardowe, jak i zdefiniowane przez użytkownika są wykonywane w konwertowaniu rzeczywistego argumentu na poprawny typ. Wykonywane inicjowanie zostało koncepcyjnie zilustrowane przez następujący kod:

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

    Koncepcyjne inicjalizacje przed wywołaniem to:

    int Temp_i = 7;
    Func( Temp_i );
    

    Należy zauważyć, że inicjalizacja jest wykonywana jakby przy użyciu składni znaku równości zamiast składni nawiasów. Kopia i została utworzona przed przekazaniem wartości do funkcji. (Aby uzyskać więcej informacji, zobacz Inicjatory i konwersje).

    W związku z tym, jeśli prototyp funkcji (deklaracja) wywołuje argument typu long, a program wywołujący dostarcza rzeczywisty argument typu int, rzeczywisty argument jest promowany przy użyciu standardowej konwersji typu na typ long (zobacz Konwersje standardowe).

    Błędem jest podawanie rzeczywistego argumentu, dla którego nie ma żadnych standardowych lub zdefiniowanych przez użytkownika konwersji do typu argumentu formalnego.

    Dla rzeczywistych argumentów typu klasy, argument formalny jest inicjowany przez wywołanie konstruktora klasy. (Zobacz Konstruktory , aby uzyskać więcej informacji na temat tych specjalnych funkcji składowych klasy).

  • Wywołanie funkcji jest wykonywane.

Poniższy fragment programu demonstruje wywołanie funkcji:

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

Gdy func jest wywoływany z main, parametr param1 formalny jest inicjowany z wartością i (i jest konwertowany na typ long odpowiadający poprawnemu typowi przy użyciu konwersji standardowej), a parametr param2 formalny jest inicjowany z wartością j (j jest konwertowany na typ double przy użyciu konwersji standardowej).

Traktowanie typów argumentów

Argumenty formalne zadeklarowane jako const typy nie mogą być zmieniane w treści funkcji. Funkcje mogą zmieniać dowolny argument, który nie jest typu const. Jednak zmiana jest lokalna dla funkcji i nie ma wpływu na wartość rzeczywistego argumentu, chyba że rzeczywisty argument był odwołaniem do obiektu nie typu const.

Poniższe funkcje ilustrują niektóre z tych pojęć:

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

Wielokropek i argumenty domyślne

Funkcje można zadeklarować tak, aby akceptowały mniej argumentów niż określono w definicji funkcji przy użyciu jednej z dwóch metod: wielokropka (...) lub argumentów domyślnych.

Wielokropek oznacza, że argumenty mogą być wymagane, ale liczba i typy nie są określone w deklaracji. Zwykle jest to słaba praktyka programowania w języku C++, ponieważ pokonuje jedną z zalet bezpieczeństwa języka C++: typu. Różne konwersje są stosowane do funkcji zadeklarowanych za pomocą wielokropka niż do tych funkcji, dla których znane są typy argumentów formalnych i rzeczywistych:

  • Jeśli rzeczywisty argument ma typ float, jest promowany do typu double przed wywołaniem funkcji.

  • Dowolny signed char typ lub signed shortunsigned charunsigned short, wyliczony typ lub pole bitowe jest konwertowane na signed int typ lub przy unsigned int użyciu promocji całkowitej.

  • Każdy argument typu klasy jest przekazywany przez wartość jako strukturę danych; kopia jest tworzona przez kopiowanie binarne zamiast wywoływania konstruktora kopiowania klasy (jeśli istnieje).

Wielokropek, jeśli jest używany, musi być zadeklarowany jako ostatni na liście argumentów. Aby uzyskać więcej informacji na temat przekazywania zmiennej liczby argumentów, zobacz omówienie va_arg, va_start i va_list w dokumentacji biblioteki czasu wykonywania.

Aby uzyskać informacje na temat domyślnych argumentów w programowaniu CLR, zobacz Zmienne listy argumentów (...) (C++/CLI).

Argumenty domyślne umożliwiają określenie wartości, którą argument powinien przyjąć, jeśli żadna z nich nie zostanie podana w wywołaniu funkcji. Poniższy fragment kodu pokazuje, jak działają argumenty domyślne. Aby uzyskać więcej informacji na temat ograniczeń dotyczących określania argumentów domyślnych, zobacz Argumenty domyślne.

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

Poprzedni program deklaruje funkcję , printktóra przyjmuje dwa argumenty. Jednak drugi argument, terminator, ma wartość domyślną , "\n". W mainsystemie pierwsze dwa wywołania zezwalają print domyślnemu drugiemu argumentowi na podanie nowego wiersza w celu zakończenia drukowanego ciągu. Trzecie wywołanie określa jawną wartość drugiego argumentu. Dane wyjściowe z programu to

hello,
world!
good morning, sunshine.

Zobacz też

Typy wyrażeń