导言
运算符是编程语言中用于执行特定操作的符号或关键字。在C++中,运算符的使用广泛且多样,掌握运算符的使用对于编写高效、简洁的代码至关重要。本教案旨在全面介绍C++中的各种运算符,帮助学习者深入理解和灵活运用。
运算符概述
运算符(Operator) 是用来对变量进行操作的符号或函数。C++中的运算符可分为多种类型,每种运算符具有特定的功能和使用规则。运算符可以单目(仅操作一个操作数)、双目(操作两个操作数)、甚至三目(操作三个操作数)等。
运算符分类
C++中的运算符可以根据功能和使用方式分为以下几类:
1. 算术运算符
用于执行基本的数学计算。
运算符 | 描述 | 示例 |
---|---|---|
+ |
加法 | a + b |
- |
减法 | a - b |
* |
乘法 | a * b |
/ |
除法 | a / b |
% |
取模(求余数) | a % b |
++ |
自增(前缀/后缀) | ++a , a++ |
-- |
自减(前缀/后缀) | --a , a-- |
示例:
int a = 10, b = 3;
int sum = a + b; // 13
int diff = a - b; // 7
int prod = a * b; // 30
int div = a / b; // 3
int mod = a % b; // 1
a++; // a = 11
--b; // b = 2
2. 关系运算符
用于比较两个值之间的关系,返回布尔值(true
或 false
)。
运算符 | 描述 | 示例 |
---|---|---|
== |
等于 | a == b |
!= |
不等于 | a != b |
> |
大于 | a > b |
< |
小于 | a < b |
>= |
大于或等于 | a >= b |
<= |
小于或等于 | a <= b |
示例:
int a = 5, b = 10;
bool result1 = (a == b); // false
bool result2 = (a < b); // true
bool result3 = (a >= b); // false
3. 逻辑运算符
用于组合或反转布尔表达式,返回布尔值。
运算符 | 描述 | 示例 | ||||
---|---|---|---|---|---|---|
&& |
逻辑与(AND) | a && b |
||||
` | ` | 逻辑或 (OR) | `a | b` | ||
! |
逻辑非(NOT) | !a |
示例:
bool a = true, b = false;
bool result1 = a && b; // false
bool result2 = a || b; // true
bool result3 = !a; // false
4. 位运算符
用于按位操作整数类型的二进制位。
运算符 | 描述 | 示例 | ||
---|---|---|---|---|
& |
按位与 | a & b |
||
` | ` | 按位或 | `a | b` |
^ |
按位异或(不等时为1) | a ^ b |
||
~ |
按位取反 | ~a |
||
<< |
左移 | a << 2 |
||
>> |
右移 | a >> 2 |
示例:
int a = 5; // 二进制:0101
int b = 3; // 二进制:0011
int andResult = a & b; // 1 (0001)
int orResult = a | b; // 7 (0111)
int xorResult = a ^ b; // 6 (0110)
int notResult = ~a; // -6 (补码)
int leftShift = a << 1; // 10 (1010)
int rightShift = a >> 1; // 2 (0010)
5. 赋值运算符
用于向变量赋值。
运算符 | 描述 | 示例 | ||
---|---|---|---|---|
= |
简单赋值 | a = b |
||
+= |
加后赋值 | a += b |
||
-= |
减后赋值 | a -= b |
||
*= |
乘后赋值 | a *= b |
||
/= |
除后赋值 | a /= b |
||
%= |
取模后赋值 | a %= b |
||
&= |
按位与后赋值 | a &= b |
||
` | =` | 按位或后赋值 | `a | = b` |
^= |
按位异或后赋值 | a ^= b |
||
<<= |
左移后赋值 | a <<= 2 |
||
>>= |
右移后赋值 | a >>= 2 |
示例:
int a = 5;
int b = 3;
a += b; // a = 8
a *= 2; // a = 16
a &= b; // a = 16 & 3 = 0
6. 复合赋值运算符
结合赋值与其他运算的运算符(如上表中所示的+=
, -=
, 等)。
示例:
int a = 10;
a += 5; // 等同于 a = a + 5; 结果 a = 15
7. 条件运算符
用于基于条件选择值。
运算符 | 描述 | 示例 |
---|---|---|
?: |
条件(三目)运算符 | a ? b : c |
示例:
int a = 10, b = 20, c;
c = (a > b) ? a : b; // c = 20
8. 递增和递减运算符
用于增加或减少变量的值,前缀和后缀形式。
运算符 | 描述 | 示例 |
---|---|---|
++ |
自增(前缀/后缀) | ++a , a++ |
-- |
自减(前缀/后缀) | --a , a-- |
示例:
int a = 5;
int b = ++a; // a = 6, b = 6
int c = a--; // a = 5, c = 6
9. 指针运算符
用于操作指针。
运算符 | 描述 | 示例 |
---|---|---|
* |
间接访问(解引用) | *ptr |
& |
取地址 | &a |
-> |
成员访问(指向对象的指针) | ptr->member |
[] |
数组下标访问 | arr[2] |
示例:
int a = 10;
int *ptr = &a;
int value = *ptr; // value = 10
10. 成员访问运算符
用于访问类或结构体的成员。
运算符 | 描述 | 示例 |
---|---|---|
. |
直接成员访问 | object.member |
-> |
指向成员的指针访问 | ptr->member |
::* |
指向成员的指针(成员指针操作符) | Class::*ptr |
示例:
struct Point {
int x;
int y;
};
Point p = {10, 20};
Point *ptr = &p;
int a = p.x; // 使用 . 运算符
int b = ptr->y; // 使用 -> 运算符
11. 其他运算符
运算符 | 描述 | 示例 |
---|---|---|
sizeof |
返回变量或类型所占字节数 | sizeof(int) |
?: |
条件(三目)运算符 | a ? b : c |
, |
逗号运算符 | a = (b, c) |
typeid |
运行时类型信息运算符 | typeid(a) |
new |
动态内存分配 | int *ptr = new int; |
delete |
动态内存释放 | delete ptr; |
示例:
int a = 5;
int size = sizeof(a); // size = 4 (通常)
int b, c;
b = (a++, a + 2); // a = 6, b = 8
运算符优先级与结合性
运算符的优先级决定了在没有括号明确指定的情况下,哪一个运算符先被计算。结合性则决定了运算符在具有相同优先级时的计算顺序(从左到右或从右到左)。
优先级表
以下是C++运算符的优先级从高到低的简要概览:
优先级 | 运算符类别 | 运算符 | 结合性 | 备注 |
---|---|---|---|---|
1 | 范围解析运算符 | :: |
左到右 | 用于访问命名空间或类的成员 |
2 | 后缀运算符 | () , [] , . , -> , ++ (后置), -- (后置) |
左到右 | 包含函数调用、数组下标、成员访问 |
3 | 一元运算符 | + , - , ! , ~ , ++ (前置), -- (前置), * (解引用), & (取地址), sizeof , typeid |
右到左 | 适用于单个操作数的运算符 |
4 | 乘法运算符 | * , / , % |
左到右 | 乘法、除法和取模运算 |
5 | 加法运算符 | + , - |
左到右 | 加法和减法运算 |
6 | 移位运算符 | << , >> |
左到右 | 位左移和位右移 |
7 | 关系运算符 | < , <= , > , >= |
左到右 | 比较运算符 |
8 | 相等运算符 | == , != |
左到右 | 判断相等与不相等 |
9 | 位与运算符 | & |
左到右 | 按位与 |
10 | 位异或运算符 | ^ |
左到右 | 按位异或 |
11 | 位或运算符 | ` | ` | 左到右 |
12 | 逻辑与运算符 | && |
左到右 | 逻辑与 |
13 | 逻辑或运算符 | ` | ` | |
14 | 条件运算符 | ?: |
右到左 | 条件(三目)运算符 |
15 | 赋值运算符 | = , += , -= , *= , /= , %= , &= , ` |
=, ^=, <<=, >>=` |
右到左 |
16 | 逗号运算符 | , |
左到右 | 逗号用于表达式中多个操作 |
表格说明
- 优先级:数字越小,优先级越高。即优先级为1的运算符最先被计算。
- 运算符类别:运算符的功能分类,帮助理解不同类型运算符的用途。
- 运算符:具体的C++运算符符号。
- 结合性:当表达式中出现多个相同优先级的运算符时,决定运算顺序的规则。
左到右
表示从左侧的操作数开始,右到左
表示从右侧的操作数开始。 - 备注:对运算符类别或特定运算符的简要说明。
运算符重载
运算符重载(Operator Overloading) 允许开发者为自定义类型(如类和结构体)定义或改变运算符的行为,使其表现得像内置类型一样。这提高了代码的可读性和可维护性。
运算符重载的规则
- 可重载运算符:几乎所有的运算符都可以被重载,但如
::
,?:
,sizeof
等运算符不能被重载。 - 至少一个操作数必须是用户定义类型:即至少有一个操作数是类、结构体或联合体类型。
- 运算符重载不改变运算符的优先级、结合性和操作数数量。
运算符重载的基本语法
运算符可以作为成员函数或友元函数进行重载。
成员函数重载示例:
class Complex {
public:
double real, imag;
Complex operator+(const Complex &c) {
Complex temp;
temp.real = real + c.real;
temp.imag = imag + c.imag;
return temp;
}
};
友元函数重载示例:
class Complex {
public:
double real, imag;
friend Complex operator+(const Complex &c1, const Complex &c2);
};
Complex operator+(const Complex &c1, const Complex &c2) {
Complex temp;
temp.real = c1.real + c2.real;
temp.imag = c1.imag + c2.imag;
return temp;
}
常见的重载运算符
- 算术运算符:
+
,-
,*
,/
,%
- 关系运算符:
==
,!=
,<
,>
,<=
,>=
- 逻辑运算符:
&&
,||
,!
- 赋值运算符:
=
,+=
,-=
,*=
,/=
- 输入输出运算符:
<<
,>>
- 索引运算符:
[]
- 函数调用运算符:
()
示例:
#include <iostream>
using namespace std;
class Complex {
public:
double real, imag;
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// 重载 + 运算符
Complex operator+(const Complex &c) {
return Complex(real + c.real, imag + c.imag);
}
// 重载 << 运算符(作为友元函数)
friend ostream& operator<<(ostream &out, const Complex &c);
};
ostream& operator<<(ostream &out, const Complex &c) {
out << c.real << " + " << c.imag << "i";
return out;
}
int main() {
Complex c1(1.2, 3.4);
Complex c2(5.6, 7.8);
Complex c3 = c1 + c2;
cout << "c1 + c2 = " << c3 << endl; // 输出: c1 + c2 = 6.8 + 11.2i
return 0;
}
练习题
1 交换两个数
题目: 使用位运算符,交换两个整数变量的值而不使用第三个变量。
答案:
#include <iostream>
int main() {
int x = 15;
int y = 27;
std::cout << "Before swap: x = " << x << ", y = " << y << std::endl;
// 交换操作
x = x ^ y;
y = x ^ y;
x = x ^ y;
std::cout << "After swap: x = " << x << ", y = " << y << std::endl;
return 0;
}
预期输出:
Before swap: x = 15, y = 27
After swap: x = 27, y = 15
解析: 通过异或运算 ^
完成变量值的交换,无需使用临时变量。
2 函数修改外部变量
题目: 编写一个函数,接受一个整数指针,使用解引用运算符修改其值为原值的平方。
答案:
#include <iostream>
void square(int* ptr) {
*ptr = (*ptr) * (*ptr);
}
int main() {
int num = 5;
std::cout << "Before: " << num << std::endl;
square(&num);
std::cout << "After: " << num << std::endl;
return 0;
}
预期输出:
Before: 5
After: 25
解析: 通过指针访问并修改原变量的值。
3 计算范围内所有元素的和
题目: 编写一个函数,接受 std::vector<int>
的迭代器范围,计算并返回范围内所有元素的和。
函数示例:
须实现如下函数,返回范围内元素求和的结果
int sumRange(std::vector<int>::iterator start, std::vector<int>::iterator end);
答案:
#include <iostream>
#include <vector>
int sumRange(std::vector<int>::iterator start, std::vector<int>::iterator end) {
int sum = 0;
while (start != end) {
sum += *start;
++start;
}
return sum;
}
int main() {
std::vector<int> numbers = {2, 4, 6, 8, 10};
int total = sumRange(numbers.begin(), numbers.end());
std::cout << "Sum: " << total << std::endl;
return 0;
}
预期输出:
Sum: 30
解析: 函数通过迭代器遍历范围,累加元素值。