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

 更新时间:2020年4月25日 17:36  点击:2060

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

    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.

[!--infotagslink--]

相关文章

  • C++ STL标准库std::vector的使用详解

    vector是表示可以改变大小的数组的序列容器,本文主要介绍了C++STL标准库std::vector的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2022-03-06
  • C++中取余运算的实现

    这篇文章主要介绍了C++中取余运算的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ string常用截取字符串方法

    这篇文章主要介绍了C++ string常用截取字符串方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++调用C#的DLL程序实现方法

    本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
  • C++中四种加密算法之AES源代码

    本篇文章主要介绍了C++中四种加密算法之AES源代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...2020-04-25
  • C++ 整数拆分方法详解

    整数拆分,指把一个整数分解成若干个整数的和。本文重点给大家介绍C++ 整数拆分方法详解,非常不错,感兴趣的朋友一起学习吧...2020-04-25
  • C++中 Sort函数详细解析

    这篇文章主要介绍了C++中Sort函数详细解析,sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变...2022-08-18
  • C++万能库头文件在vs中的安装步骤(图文)

    这篇文章主要介绍了C++万能库头文件在vs中的安装步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ bitset用法

    这篇文章主要介绍了C++ bitset用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • 浅谈C++中的string 类型占几个字节

    本篇文章小编并不是为大家讲解string类型的用法,而是讲解我个人比较好奇的问题,就是string 类型占几个字节...2020-04-25
  • C++ Eigen库计算矩阵特征值及特征向量

    这篇文章主要为大家详细介绍了C++ Eigen库计算矩阵特征值及特征向量,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-04-25
  • C++ pair的用法实例详解

    这篇文章主要介绍了C++ pair的用法实例详解的相关资料,需要的朋友可以参考下...2020-04-25
  • VSCode C++多文件编译的简单使用方法

    这篇文章主要介绍了VSCode C++多文件编译的简单使用方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-29
  • C++中的循环引用

    虽然C++11引入了智能指针的,但是开发人员在与内存的斗争问题上并没有解放,如果我门实用不当仍然有内存泄漏问题,其中智能指针的循环引用缺陷是最大的问题。下面通过实例代码给大家介绍c++中的循环引用,一起看看吧...2020-04-25
  • C++随机点名生成器实例代码(老师们的福音!)

    这篇文章主要给大家介绍了关于C++随机点名生成器的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++如何删除map容器中指定值的元素详解

    map容器是C++ STL中的重要一员,删除map容器中value为指定元素的问题是我们经常与遇到的一个问题,下面这篇文章主要给大家介绍了关于利用C++如何删除map容器中指定值的元素的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。...2020-04-25
  • C++ 约瑟夫环问题案例详解

    这篇文章主要介绍了C++ 约瑟夫环问题案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...2021-08-15
  • C++中cin的用法详细

    这篇文章主要介绍了C++中cin的用法详细,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • 基于C++中常见编译错误的总结详解

    本篇文章是对C++中的常见编译错误进行了详细的分析介绍,需要的朋友参考下...2020-04-25
  • c++优先队列(priority_queue)用法详解

    这篇文章主要介绍了c++优先队列(priority_queue)用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25