详解C++语言中的加法运算符与赋值运算符的用法
加法运算符:+和-
语法
expression+expression expression–expression
备注
相加运算符为:
- 加(+)
- 减(–)
这些二进制运算符具有从左至右的关联性。
相加运算符采用算术或指针类型的操作数。加法(+)运算符的结果是操作数之和。减法(–)运算符的结果是操作数之差。如果一个操作数是指针或两个操作数都是指针,则它们必须是指向对象的指针,而不是指向函数的指针。如果两个操作数都是指针,则结果没有意义,除非它们是指向同一数组中的对象的指针。
相加运算符采用arithmetic、integral和scalar类型的操作数。下表定义了这些操作数。
用于相加运算符的类型
S.N. | 构造函数&描述 |
---|---|
arithmetic | 整型和浮点类型统称为“算术”类型。 |
integral | 所有大小(long、short)和枚举数的char和int类型为“整数”类型。 |
scalar | 标量操作数是算术类型或指针类型的操作数。 |
这些运算符的合法组合为:
- 算术+算术
- 标量+整数
- 整数+标量
- 算术–算术
- 标量–标量
请注意,加法和减法不是等效运算。
//expre_Additive_Operators.cpp //compilewith:/EHsc #include<iostream> #defineSIZE5 usingnamespacestd; intmain(){ inti=5,j=10; intn[SIZE]={0,1,2,3,4}; cout<<"5+10="<<i+j<<endl <<"5-10="<<i-j<<endl; //usepointerarithmeticonarray cout<<"n[3]="<<*(n+3)<<endl; }
指针加法
在加法运算中,如果其中一个操作数是指向对象数组的指针,则另一个操作数必须是整型。结果为与原始指针类型相同的指针和指向另一个数组元素的指针。以下代码片段阐述了此概念:
shortIntArray[10];//Objectsoftypeshortoccupy2bytes
short*pIntArray=IntArray;
for(inti=0;i<10;++i) { *pIntArray=i; cout<<*pIntArray<<"\n"; pIntArray=pIntArray+1; }
虽然将整数值1添加到pIntArray,但这并不表示“将1添加到该地址”,而是指“调整指针使其指向数组中的下一个对象”,而该对象恰好是在2字节(或者sizeof(int))之外。
注意
在C++程序中很少找到pIntArray=pIntArray+1形式的代码;若要实现递增,以下形式更可取:pIntArray++或pIntArray+=1。
指针减法
如果两个操作数都是指针,则减法运算的结果就是两个操作数之差(在数组元素中)。减法表达式产生类型ptrdiff_t(在标准包含文件STDDEF.H中定义)的带符号的整数结果。
其中一个操作数可以是整型,条件是该操作数是第二操作数。减法的结果的类型与原始指针的类型相同。减法的值是指向第(n–i)个数组元素的指针,其中n是由原始指针指向的元素,而i是第二操作数的整数值。
赋值运算符
语法
expressionassignment-operatorexpression assignment-operator:oneof =*=/=%=+=–=<<=>>=&=^=|=
备注
赋值运算符将值存储在左操作数指定的对象中。有两种赋值操作:简单赋值,其中第二个操作数的值存储在第一个操作数指定的对象中;复合赋值,其中先执行算术、移位或位运算,然后再存储结果。下表中除=运算符之外的所有其他赋值运算符都是复合赋值运算符。
赋值运算符
运算符 | 含义 |
---|---|
= | 整型和浮点类型统称为“算术”类型。 |
*= | 所有大小(long、short)和枚举数的char和int类型为“整数”类型。 |
/= | 标量操作数是算术类型或指针类型的操作数。 |
%= | 整型和浮点类型统称为“算术”类型。 |
+= | 所有大小(long、short)和枚举数的char和int类型为“整数”类型。 |
–= | 标量操作数是算术类型或指针类型的操作数。 |
<<= | 将第一个操作数的值按第二个操作数的值指定的位数左移;将结果存储在第一个操作数指定的对象中。 |
>>= | 将第一个操作数的值按第二个操作数的值指定的位数右移;将结果存储在第一个操作数指定的对象中。 |
&= | 获取第一个和第二个操作数的按位“与”;将结果存储在第一个操作数指定的对象中。 |
^= | 获取第一个和第二个操作数的按位“异或”;将结果存储在第一个操作数指定的对象中。 |
|= | 获取第一个和第二个操作数的按位“与或”;将结果存储在第一个操作数指定的对象中。 |
运算符关键字
三个复合赋值运算符具有文本等效项。它们是:
运算符 | 等效 |
---|---|
&= | and_eq |
|= | or_eq |
^= | xor_eq |
在您的程序中有两种访问这些运算符关键字的方法:包括标头文件iso646.h或使用/Za(禁用语言扩展)编译器选项进行编译。
//expre_Assignment_Operators.cpp //compilewith:/EHsc //Demonstrateassignmentoperators #include<iostream> usingnamespacestd; intmain(){ inta=3,b=6,c=10,d=0xAAAA,e=0x5555; a+=b;//ais9 b%=a;//bis6 c>>=1;//cis5 d|=e;//Bitwise--dis0xFFFF cout<<"a=3,b=6,c=10,d=0xAAAA,e=0x5555"<<endl <<"a+=byields"<<a<<endl <<"b%=ayields"<<b<<endl <<"c>>=1yields"<<c<<endl <<"d|=eyields"<<hex<<d<<endl; }
简单赋值
简单赋值运算符(=)将使第二个操作数的值存储在第一个操作数指定的对象中。如果两个对象都是算术类型,则在存储值之前,正确的操作数将转换为左侧的类型。
常量和可变类型的对象可赋给可变类型的左值或者既不是常量类型也不是可变类型的左值。
对类类型(结构、联合和类类型)的对象的赋值由名为operator=的函数执行。此运算符函数值的默认行为是执行按位复制;但是,可使用重载运算符修改此行为。(有关详细信息,请参阅重载运算符。)
任何从给定基类明确派生的类的对象均可赋给基类的对象。反之则不然,因为有一个隐式转换,它能从派生类转换到基类,但不能从基类转换到派生类。例如:
//expre_SimpleAssignment.cpp //compilewith:/EHsc #include<iostream> usingnamespacestd; classABase { public: ABase(){cout<<"constructingABase\n";} }; classADerived:publicABase { public: ADerived(){cout<<"constructingADerived\n";} }; intmain() { ABaseaBase; ADerivedaDerived; aBase=aDerived;//OK aDerived=aBase;//C2679 }
对引用类型的赋值的行为方式就像对引用所指向的对象进行赋值一样。
对于类类型对象,赋值与初始化不同。若要演示不同赋值和初始化的工作方式,请考虑以下代码
UserType1A; UserType2B=A;
上面的代码显示了一个初始值设定项;它调用了采用UserType2类型的参数的UserType1的构造函数。给定以下代码
UserType1A; UserType2B; B=A;
赋值语句
B=A;
可能具有以下效果之一:
将为UserType2调用函数operator=,前提是operator=提供UserType1参数。
如果存在显式转换函数UserType1::operatorUserType2,则调用该函数。
调用采用UserType2::UserType2参数并复制结果的构造函数UserType1,前提是存在此类构造函数。
复合赋值
显示在的表中的复合赋值运算符以e1op=e2的形式指定,其中e1是非常量类型的可修改左值,而e2是以下项之一:
算术类型
指针(如果op为+或–)
e1op=e2形式的行为方式与e1=e1ope2的相同,但e1只计算一次。
对枚举类型的复合赋值将生成错误消息。如果左操作数属于指针类型,则右操作数必须属于指针类型或必须是计算结果为0的常量表达式。如果左操作数属于整数类型,则右操作数不能属于指针类型。
赋值运算符的结果
赋值后,赋值运算符将返回由左操作数指定的对象的值。获得的类型是左操作数的类型。赋值表达式的结果始终为左值。这些运算符具有从右向左的关联性。左操作数必须为可修改的左值。
在ANSIC中,赋值表达式的结果不是左值。因此,合法的C++表达式(a+=b)+=c在C中是非法的。