详解C++编程中的主表达式与后缀表达式编写基础_C 语言

主表达式
主表达式是更复杂的表达式的构造块。它们是文本、名称以及范围解析运算符 (::) 限定的名称。主表达式可以具有以下任一形式:

    literal
this
:: name
name
( expression )

literal 是常量主表达式。其类型取决于其规范的形式。
this 关键字是指向类对象的指针。它在非静态成员函数中可用,并指向为其调用函数的类的实例。 this 关键字只能在类成员函数体的外部使用。
this 指针的类型是未特别修改 this 指针的函数中的 type *const(其中 type 是类名)。以下示例演示成员函数声明以及 this 的类型:

// expre_Primary_Expressions.cpp
// compile with: /LD
class Example
{
public:
  void Func();     // * const this
  void Func() const;  // const * const this
  void Func() volatile; // volatile * const this
};

范围解析运算符 (::) 后跟名称构成了主表达式。此类名称必须是全局范围内的名称,而不是成员名称。此表达式的类型由名称的声明决定。如果声明的名称是左值,则该类型是左值(即,它可以出现在赋值运算符表达式的左侧)。范围解析运算符允许引用全局名称,即使该名称隐藏在当前范围中也如此。
用括号括起的表达式是与不带括号的表达式具有相同的类型和值的主表达式。如果不带括号的表达式是左值,则用括号括起的表达式也是左值。
在上面给出的主表达式语法的上下文中,name 表示为 name 描述的语法中的任何内容,不过,当在名称前使用范围解析运算符时,不允许使用只能在类中出现的名称的类型。这包括用户定义的转换函数名称和析构函数名称。
主表达式的示例包括:

100 // literal
'c' // literal
this // in a member function, a pointer to the class instance
::func // a global function
::operator + // a global operator function
::A::B // a global qualified name
( i + 1 ) // a parenthesized expression

下面的示例是所有考虑的 name 以及各种形式的主表达式:

MyClass // a identifier
MyClass::f // a qualified name
operator = // an operator function name
operator char* // a conversion operator function name
~MyClass // a destructor name
A::B  // a qualified name
A<int> // a template id

后缀表达式

后缀表达式包含主表达式或者其中的后缀运算符跟在主表达式之后的表达式。 下表列出了后缀运算符。
后缀运算符
运算符名称
运算符表示法
下标运算符
[ ]
函数调用运算符
( )
显式类型转换运算符
type-name ( )
成员访问运算符
. 或 –>
后缀递增运算符
++
后缀递减运算符
––
以下语法描述了可能的后缀表达式:

     primary-expression
postfix-expression [ expression ]
postfix-expression ( expression-list)
simple-type-name ( expression-list)
postfix-expression . name
postfix-expression –> name
postfix-expression ++
postfix-expression ––
cast-keyword < typename > (expression )
typeid ( typename )

上面的 postfix-expression 可能是主表达式或另一个后缀表达式。 请参阅主表达式。 后缀表达式从左到右进行分组,这允许表达式按如下方式链接起来:
func(1)->GetValue()++
在上面的表达式中,func 是主表达式,func(1) 是函数后缀表达式,func(1)->GetData 是指定类成员的后缀表达式,func(1)->GetData() 是另一个函数后缀表达式,整个表达式是增加 GetData 的返回值的后缀表达式。 该表达式的整体含义是作为参数传递 1 的 "call func,并作为返回值获取一个指向类的指针。 然后调用此类上的 GetValue(),接着递增返回的值。
上面列出的表达式是赋值表达式,这意味着这些表达式的结果必须为右值。
后缀表达式形式
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 )
{
}

当从 main 调用 func 时,将使用 param1(i 将转换为类型 ilong 以对应使用标准转换的正确类型)的值初始化形参 ,并使用 param2(j 将转换为使用标准转换的类型 jdouble)的值初始化形参 。
参数类型的处理
不能在函数主题内更改声明为 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++ 编程做法,因为它使您无法获得 C++ 的一个优点,即类型安全。 不同的转换将应用于使用省略号声明的函数,而不是应用于那些已知其形参和实参类型的函数:
如果实参的类型为浮点,则在函数调用前将其提升为双精度类型。
使用整型提升将所有有符号或无符号的 char、short、枚举类型或位域转换为有符号或无符号的 int。
类类型的所有参数都作为数据结构通过值进行传递;副本是由二进制复制创建的,而不是通过调用类的复制构造函数(如果存在)创建的。
如果使用省略号,则必须在参数列表中最后声明它。 

如果函数调用中没有提供值,则可通过默认参数指定参数应采用的值。 以下代码片段演示默认参数的工作方式。

// expre_Ellipses_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。 而第二个参数 terminator 具有默认值 "\n"。 在 main 中,对 print 的前两个调用允许默认的第二个参数提供新行以终止打印的字符串。 第三个调用为第二个参数指定显式值。 该程序的输出为

hello,
world!
good morning, sunshine.

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索c++
, 主表达式
后缀表达式
后缀表达式、后缀表示的算术表达式、后缀表达式求值、中缀转后缀表达式、前缀中缀后缀表达式,以便于您获取更多的相关知识。

时间: 2024-08-03 08:54:32

详解C++编程中的主表达式与后缀表达式编写基础_C 语言的相关文章

详解C++编程中的单目运算符重载与双目运算符重载_C 语言

C++单目运算符重载 单目运算符只有一个操作数,如!a,-b,&c,*p,还有最常用的++i和--i等.重载单目运算符的方法与重载双目运算符的方法是类似的.但由于单目运算符只有一个操作数,因此运算符重载函数只有一个参数,如果运算符重载函数作为成员函数,则还可省略此参数. 下面以自增运算符"++"为例,介绍单目运算符的重载. [例] 有一个Time类,包含数据成员minute(分)和sec(秒),模拟秒表,每次走一秒,满60秒进一分钟,此时秒又从0开始算.要求输出分和秒的值. #

详解C++编程中多级派生时的构造函数和访问属性_C 语言

C++多层派生时的构造函数 一个类不仅可以派生出一个派生类,派生类还可以继续派生,形成派生的层次结构.在上面叙述的基础上,不难写出在多级派生情况下派生类的构造函数. 通过例下面的程序,读者可以了解在多级派生情况下怎样定义派生类的构造函数.相信大家完全可以自己看懂这个程序. [例] 多级派生情况下派生类的构造函数. #include <iostream> #include<string> using namespace std; class Student//声明基类 { publi

详解Java编程中的策略模式_java

策略模式属于对象的行为模式.其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换.策略模式使得算法可以在不影响到客户端的情况下发生变化. 策略模式的结构 策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理.策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类.用一句话来说,就是:"准备一组算法,并将每一个算法封装起来,使得它们可以互换".下面就以一个示意性的实现讲解策略模式实例的结构. 这个

详解Java编程中的反射在Android开发中的应用_Android

反射定义 "反射"(Reflection)能够让运行于JVM中的程序检测和修改运行时的行为.为何需要反射 反射带来的好处包括:     在运行时检测对象的类型.     动态构造某个类的对象.     检测类的属性和方法.     任意调用对象的方法.     修改构造函数.方法.属性的可见性. 反射方法Method getDeclaredMethod方法 声明如下: public Method getDeclaredMethod(String name, Class<?>

详解Java编程中向量(Vector)的应用_java

Vector(向量)是 java.util 包中的一个类,该类实现了类似动态数组的功能. 向量和数组相似,都可以保存一组数据(数据列表).但是数组的大小是固定的,一旦指定,就不能改变,而向量却提供了一种类似于"动态数组"的功能,向量与数组的重要区别之一就是向量的容量是可变的. 可以在向量的任意位置插入不同类型的对象,无需考虑对象的类型,也无需考虑向量的容量. 向量和数组分别适用于不同的场合,一般来说,下列场合更适合于使用向量: 如果需要频繁进行对象的插入和删除工作,或者因为需要处理的对

详解C++编程中表达式的语义与计算顺序_C 语言

表达式根据其运算符的优先级和分组来计算. 计算顺序请看以下示例: // expre_pluslang__pluslang_Order_of_Evaluation.cpp // compile with: /EHsc #include <iostream> using namespace std; int main() { int a = 2, b = 4, c = 9; cout << a + b * c << "\n"; cout <<

详解C++编程中对于函数的基本使用_C 语言

形式参数和实际参数 在调用函数时,大多数情况下,函数是带参数的.主调函数和被调用函数之间有数据传递关系.前面已提到:在定义函数时函数名后面括号中的变量名称为形式参数(formal parameter,简称形参),在主调函数中调用一个函数时,函数名后面括号中的参数(可以是一个表达式)称为实际参数(actual parameter,简称实参). [例]调用函数时的数据传递. #include <iostream> using namespace std; int max(int x,int y)

详解C++编程中数组的基本用法_C 语言

可以使用数组下标操作符 ([ ]) 访问数组的各个元素. 如果在无下标表达式中使用一维数组,组名计算为指向该数组中的第一个元素的指针. // using_arrays.cpp int main() { char chArray[10]; char *pch = chArray; // Evaluates to a pointer to the first element. char ch = chArray[0]; // Evaluates to the value of the first e

详解C++编程中的文件流与字符串流_C 语言

C++文件流类与文件流对象 文件流是以外存文件为输入输出对象的数据流.输出文件流是从内存流向外存文件的数据,输入文件流是从外存文件流向内存的数据.每一个文件流都有一个内存缓冲区与之对应. 请区分文件流与文件的概念,不用误以为文件流是由若干个文件组成的流.文件流本身不是文件,而只是以文件为输入输出对象的流.若要对磁盘文件输入输出,就必须通过文件流来实现. 在C++的I/O类库中定义了几种文件类,专门用于对磁盘文件的输入输出操作. 除了标准输入输出流类istream.ostream和iostream