Постфиксные выражения
Постфиксные выражения состоят из основных выражений или выражений, в которых постфиксные операторы следуют за основным выражением. Постфиксные операторы перечислены в следующей таблице.
Постфиксные операторы
Имя оператора | Нотация оператора |
---|---|
Оператор subscript | [ ] |
Оператор вызова функции | ( ) |
Оператор явного преобразования типов | type-name ( ) |
Оператор доступа к членам | . или -> |
Оператор добавочного увеличения postfix | ++ |
Оператор декремента postfix | -- |
Следующий синтаксис описывает возможные постфиксные выражения:
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 )
Приведенное выше выражение постфикса может быть первичным или другим выражением постфикса. Постфиксные выражения группируются слева направо, делая возможным следующее связывание выражений.
func(1)->GetValue()++
В приведенном выше выражении func
является первичным выражением, func(1)
является выражением постфикса функции, func(1)->GetValue
является выражением postfix, указывающим член класса, является другим выражением постфикса функции, func(1)->GetValue()
и все выражение является выражением постфикса, добавив возвращаемое значение GetValue. Значение выражения в целом имеет следующий смысл: "вызовите функцию, передающую 1 в качестве аргумента, и получите указатель на класс в качестве возвращаемого значения. Затем вызовите этот класс, а затем увеличьте GetValue()
возвращаемое значение.
Перечисленные выше выражения — это выражения присваивания, что означает, что результат этих выражений должен представлять собой r-значение.
Форма постфиксного выражения
simple-type-name ( expression-list )
показывает вызов конструктора. Если simple-type-name — это фундаментальный тип, список выражений должен представлять собой отдельное выражение, и это выражение обозначает приведение значения выражения к фундаментальному типу. Данный тип выражения приведения копирует конструктор. Поскольку эта форма позволяет создавать фундаментальные типы и классы с использованием одного и того же синтаксиса, эта форма особенно полезна при определении шаблонных классов.
Ключевое слово cast-keyword является одним из dynamic_cast
или static_cast
reinterpret_cast
. Дополнительные сведения можно найти в dynamic_cast
, static_cast
а reinterpet_cast
также .
Оператор typeid
считается выражением постфикса. См . оператор typeid.
Формальные и фактические аргументы
Вызовы программ передают информацию вызываемой функции в "фактических аргументах". Вызываемые функции получают доступ к информации с помощью соответствующих "формальных аргументов".
При вызове функции выполняются следующие задачи.
Вычисляются все фактические аргументы (предоставляемые вызывающим объектом). Эти аргументы вычисляются в произвольном порядке, но все аргументы вычисляются и все побочные эффекты завершаются перед переходом в функцию.
Каждый формальный аргумент инициализируется с соответствующим фактическим аргументом в списке выражений. (Формальный аргумент — это аргумент, объявленный в заголовке функции и используемый в тексте функции.) Преобразования выполняются так, как будто путем инициализации — при преобразовании фактического аргумента в правильный тип выполняются как стандартные, так и определяемые пользователем преобразования. В общем виде выполненная инициализация показана в следующем коде.
void Func( int i ); // Function prototype ... Func( 7 ); // Execute function call
Ниже представлены концептуальные инициализации до вызова.
int Temp_i = 7; Func( Temp_i );
Обратите внимание, что инициализация выполняется таким образом, как если бы использовался синтаксис со знаком равенства, а не синтаксис с круглыми скобками. Копия
i
создается до передачи значения в функцию. (Дополнительные сведения см. в разделе Инициализаторы и преобразования).Таким образом, если прототип функции (объявление) вызывает аргумент типа и если вызывающая программа предоставляет фактический аргумент типа
long
int
, фактический аргумент повышен с помощью стандартного преобразования типов в типlong
(см. стандартные преобразования).Предоставление фактического аргумента при отсутствии стандартного или пользовательского преобразования в тип формального аргумента будет ошибкой.
В случае фактических аргументов типа класса формальный аргумент инициализируется путем вызова конструктора класса. (См. раздел Конструкторы для получения дополнительных данных об этих функциях-членах класса.)
Выполняется вызов функции.
В следующем фрагменте программного кода показан вызов функции.
// 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 )
{
}
При func
вызове из main формальный параметр param1
инициализируется со значением i
(i
преобразуется в тип long
для соответствия правильному типу с помощью стандартного преобразования), а формальный параметр param2
инициализируется со значением j
(j
преобразуется в тип double
с помощью стандартного преобразования).
Работа с типами аргументов
Формальные аргументы, объявленные как const
типы, нельзя изменить в теле функции. Функции могут изменять любой аргумент, который не является типом const
. Однако изменение является локальным для функции и не влияет на значение фактического аргумента, если фактический аргумент не был ссылкой на объект не типа const
.
Некоторые из этих понятий показаны на примере следующих функций.
// 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;
}
Многоточие и аргументы по умолчанию
Чтобы функции принимали меньше аргументов, чем указано в определении функции, их можно определять, используя многоточие (...
) или аргументы по умолчанию.
Многоточие указывает, что аргументы могут потребоваться, но число и типы не указаны в объявлении. Это обычно плохой стиль программирования на языке C++, поскольку он сводит на нет одно из преимуществ этого языка: безопасность типа. Различные преобразования применяются к функциям, объявленным с многоточием, чем к тем функциям, для которых известны формальные и фактические типы аргументов:
Если фактический аргумент имеет тип
float
double
, он повышен до вызова функции.Любое
signed char
илиunsigned char
signed short
unsigned short
перечисленное или перечисленное поле или битовое поле преобразуется в одноsigned int
или целочисленноеunsigned int
повышение.Любой аргумент типа класса передается по значению в виде структуры данных; копия создается путем двоичного копирования, а не путем вызова конструктора копии класса (если он имеется).
Многоточие, если используется, должно быть объявлено последним в списке аргументов. Дополнительные сведения о передаче переменного числа аргументов см. в обсуждении va_arg, va_start и va_list в справочнике по библиотеке времени выполнения.
Сведения о аргументах по умолчанию в программировании среды CLR см. в статьях "Списки аргументов переменных" (...) (C++/CLI).
Аргументы по умолчанию позволяют задать значение, которое должен принять аргумент, если в вызове функции значение не передано. В следующем фрагменте кода показано, как работают аргументы по умолчанию. Дополнительные сведения об ограничениях на указание аргументов по умолчанию см. в разделе "Аргументы по умолчанию".
// 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;
}
Представленная выше программа объявляет функцию print
, принимающую два аргумента. Однако второй аргумент, терминатор, имеет значение "\n"
по умолчанию. В main
первых двух вызовах, позволяющих print
второму аргументу по умолчанию предоставить новую строку для завершения печатной строки. В третьем вызове указывается явное значение второго аргумента. После выполнения этой программы выводится следующий результат:
hello,
world!
good morning, sunshine.