Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

操作符(Operators)

操作符(Operator)是 C++ 表达式的核心组成部分,用于对操作数(Operand)进行各种运算、比较或逻辑处理。 在编译阶段,操作符会被转化为相应的汇编指令或函数调用(例如运算符重载时)。

C++ 拥有丰富的操作符体系,并且允许程序员通过运算符重载(operator overloading)定义自定义类型的操作方式,从而实现与内置类型一致的自然语法。

一、操作符的分类

类别示例用途
算术操作符+, -, *, /, %数值计算
自增/自减操作符++, --累加或递减
关系操作符==, !=, <, >, <=, >=比较
逻辑操作符&&, ||, !逻辑判断
位操作符&, |, ^, ~, <<, >>位级运算
赋值操作符=, +=, -=, *=, /=, %=赋值与复合赋值
条件运算符?:三目条件判断
逗号运算符,顺序求值
成员操作符., ->, .*, ->*成员访问
指针与地址操作符*, &指针解引用与取地址
类型转换操作符(type), static_cast, dynamic_cast类型转换
其他特殊操作符sizeof, typeid, new, delete特殊用途

二、算术操作符(Arithmetic Operators)

1. 基本算术运算

操作符含义示例
+加法a + b
-减法a - b
*乘法a * b
/除法a / b
%取余(模运算)a % b

示例:

int a = 10, b = 3;
cout << a + b << endl; // 13
cout << a - b << endl; // 7
cout << a * b << endl; // 30
cout << a / b << endl; // 3
cout << a % b << endl; // 1

2. 注意事项

  • 整数除法:两个整数相除结果仍为整数,小数部分会被截断。

  • 浮点除法:若任一操作数为浮点型,则结果为浮点数。

  • 取余运算 %:仅适用于整数类型。

  • 负数取余:结果的符号与被除数相同,例如:

    cout << (-7) % 4; // 输出 -3
    

三、自增与自减操作符(++--

1. 区分前置与后置

形式名称求值顺序示例
++i前置自增先自增再返回值int a = 1; cout << ++a; // 输出 2
i++后置自增先返回值再自增int a = 1; cout << a++; // 输出 1

同理适用于 --

2. 编译层面的区别

前置自增:

int& operator++(int& i) { i += 1; return i; }

后置自增:

int operator++(int& i, int) { int old = i; ++i; return old; }

因此后置版本通常会创建临时对象,性能略低。

四、关系操作符(Relational Operators)

用于比较两个值的大小或相等性,结果为 bool 类型。

int a = 5, b = 10;
cout << (a < b) << endl;  // 1
cout << (a == b) << endl; // 0
操作符含义示例
==等于a == b
!=不等于a != b
<小于a < b
>大于a > b
<=小于等于a <= b
>=大于等于a >= b

五、逻辑操作符(Logical Operators)

逻辑操作符用于布尔表达式组合,返回 truefalse

操作符含义示例特性
&&逻辑与(x > 0 && y > 0)短路:若左侧为假,右侧不求值
||逻辑或(x < 0 || y < 0)短路:若左侧为真,右侧不求值
!逻辑非!flag取反

短路求值(short-circuit evaluation)是逻辑运算的重要特性,它不仅提升性能,也避免非法运算(例如除零)。

if (ptr != nullptr && *ptr > 10)
    cout << "安全访问";

六、位操作符(Bitwise Operators)

位操作符直接作用于整数的二进制表示

操作符含义示例
&按位与a & b
``按位或`ab`
^按位异或a ^ b
~按位取反~a
<<左移a << n (相当于乘以 2ⁿ)
>>右移a >> n (相当于除以 2ⁿ)

示例:

unsigned int a = 5;  // 00000101
unsigned int b = 3;  // 00000011
cout << (a & b);     // 00000001 -> 1
cout << (a | b);     // 00000111 -> 7
cout << (a ^ b);     // 00000110 -> 6
cout << (~a);        // 11111010 -> 取反

注意:

  • 位移运算的右操作数必须为非负;
  • 有符号右移的高位填充由实现定义;
  • 通常使用无符号类型进行位操作以避免歧义。

七、赋值与复合赋值操作符(Assignment Operators)

1. 基本赋值

int x = 10;

2. 复合赋值

操作符等价形式
+=a = a + b
-=a = a - b
*=a = a * b
/=a = a / b
%=a = a % b
&=a = a & b
`=``a = ab`
^=a = a ^ b
<<=a = a << b
>>=a = a >> b

复合赋值的优点是只计算一次左值,因此在复杂左值表达式中效率更高:

arr[getIndex()] += 10; // getIndex() 只调用一次

八、条件运算符(Ternary Operator)

三目运算符语法:

条件 ? 表达式1 : 表达式2;

示例:

int max = (a > b) ? a : b;

等价于:

if (a > b)
    max = a;
else
    max = b;

注意:

  • 运算符返回一个值,因此可嵌入表达式;
  • 但应避免多层嵌套,影响可读性。

九、逗号运算符(Comma Operator)

逗号运算符从左到右依次求值,整个表达式的结果是最后一个表达式的值

int a = (b = 3, b + 2); // b=3执行后,再计算b+2,a=5

for 循环中常见:

for (int i = 0, j = 10; i < j; ++i, --j)
    cout << i << " " << j << endl;

十、成员与指针操作符(Member & Pointer Operators)

操作符含义示例
.访问对象成员obj.member
->访问指针所指对象的成员ptr->member
.*访问对象的成员指针(obj.*ptrMember)
->*通过指针访问成员指针(ptr->*ptrMember)

示例:

struct Test { int x; void show() { cout << x; } };
Test t{42};
Test* p = &t;
cout << t.x;    // 使用 .
cout << p->x;   // 使用 ->

十一、指针相关操作符

操作符作用示例
&取地址int* p = &x;
*解引用cout << *p;

这两个符号在声明与使用中含义不同:

int* p;   // 声明指针类型
*p = 10;  // 解引用赋值

十二、类型转换操作符(Cast Operators)

1. C 风格强制类型转换

int a = 10;
double b = (double)a;

2. C++ 风格强制类型转换

操作符用途
static_cast<T>(expr)编译期已知的安全类型转换
dynamic_cast<T>(expr)用于多态类型的安全向下转换(运行期检查)
const_cast<T>(expr)去除或添加 const 属性
reinterpret_cast<T>(expr)强制重解释类型(高风险)

示例:

Base* b = new Derived();
Derived* d = dynamic_cast<Derived*>(b); // 安全类型检查

十三、其他特殊操作符

1. sizeof

返回对象或类型的字节大小,结果类型为 size_t

cout << sizeof(int); // 通常为4

对数组时返回整个数组的大小,而不是指针大小:

int arr[10];
cout << sizeof(arr); // 40 (假设int为4字节)

2. typeid

用于在运行时获取类型信息,常与 RTTI(运行时类型识别)配合使用。

#include <typeinfo>
int a = 5;
cout << typeid(a).name(); // 输出类型名

3. newdelete

动态内存分配与释放:

int* p = new int(10);
delete p;

int* arr = new int[5];
delete[] arr;

new 会自动调用构造函数,而 delete 调用析构函数。

十四、运算符优先级与结合性

优先级(高→低)操作符结合方向
1::左到右
2() [] -> . ++ --左到右
3! ~ ++ -- + - (type) * & sizeof new delete右到左
4* / %左到右
5+ -左到右
6<< >>左到右
7< <= > >=左到右
8== !=左到右
9&左到右
10^左到右
11|左到右
12&&左到右
13||左到右
14?:右到左
15=, +=, -=, *=, /=, %=右到左
16,左到右

建议使用括号明确运算顺序,尤其在混合表达式中。

十五、运算符重载(Operator Overloading)

C++ 允许为自定义类型定义运算符行为。例如:

class Vector {
public:
    int x, y;
    Vector(int x, int y): x(x), y(y) {}
    Vector operator+(const Vector& v) const {
        return Vector(x + v.x, y + v.y);
    }
};

使用:

Vector a(1, 2), b(3, 4);
Vector c = a + b; // 等价于 a.operator+(b)

注意:

  • 不能重载 .::?:sizeof
  • 运算符重载不会改变操作符优先级;
  • 应保证语义一致性(例如重载 == 时应与 != 保持逻辑对称)。