组合运算符和运算对象
组合运算符是指将两个或多个操作数结合在一起进行运算的符号。在C++中,常见的组合运算符包括算术运算符(如+
, -
, *
, /
, %
)、关系运算符(如<
, >
, <=
, >=
, ==
, !=
)和逻辑运算符(如&&
, ||
, !
)等。
- int a = 5, b = 10;
- int sum = a + b; // '+' 是一个组合运算符,a 和 b 是运算对象
运算对象转换
在表达式中,不同类型的运算对象在进行运算时,可能会自动转换为同一类型,以确保运算的正确性。这种转换可以是隐式转换或显式转换。
- int a = 5;
- double b = 3.2;
- double result = a + b; // a 自动转换为 double 类型
- double pi = 3.14;
- int int_pi = static_cast<int>(pi); // 使用 static_cast 进行显式转换
重载运算符
C++允许用户定义的类型重载运算符。重载运算符使用户定义的类型能够像内置类型一样进行运算。例如,可以为类定义+
运算符以实现两个对象的相加。
左值和右值
左值(lvalue)表示一个对象的身份,可以位于赋值运算符的左侧。右值(rvalue)表示一个对象的值,通常位于赋值运算符的右侧,右值通常是一个“将亡值”,一般情况下不能够获取到它的地址。
运算符的优先级决定了表达式中运算符的计算顺序。结合律决定了具有相同优先级的运算符的结合顺序。
优先级
优先级高的运算符先计算。例如,乘法运算符*
的优先级高于加法运算符+
,因此在表达式a + b * c
中,b * c
会先计算。
- int a = 5, b = 10, c = 3;
- int result = a + b * c; // 先计算 b * c,然后计算 a + (b * c)
结合律
结合律分为左结合和右结合。左结合表示从左到右进行计算,右结合表示从右到左进行计算。例如,赋值运算符=
是右结合的,而加法运算符+
是左结合的。
- int a = 5, b = 10, c = 15;
- int result = a - b + c; // 先计算 a - b,然后计算 (a - b) + c,左结合
求值顺序与运算符的优先级和结合律密切相关,但并不是完全由优先级和结合律决定。C++标准并不严格规定所有表达式的求值顺序,这可能导致某些情况下的未定义行为。
运算符的优先级和结合律的关系
优先级决定了哪些运算符先计算,而结合律决定了相同优先级的运算符的计算顺序。理解优先级和结合律有助于正确分析和编写复杂表达式。
- int a = 1, b = 2, c = 3;
- int result = a + b * c; // 先计算 b * c(优先级高),然后计算 a + (b * c)
未定义的求值顺序
有些表达式的求值顺序未定义,特别是涉及到副作用的表达式。这可能导致不同编译器生成不同的结果,因此编写代码时应避免这种情况。
- int i = 0;
- int result = i++ + ++i; // 未定义行为,不同编译器可能产生不同结果
为了确保表达式的求值顺序明确,可以使用括号或将复杂表达式分解为简单的子表达式。
- int i = 0;
- int temp1 = i++;
- int temp2 = ++i;
- int result = temp1 + temp2; // 确保求值顺序明确
重点:
难点:
- #include
-
- int main() {
- int a = 5;
- int b = 10;
- int result = a + b * 2; // 乘法优先于加法
-
- std::cout << "result: " << result << std::endl; // 输出 25
- return 0;
- }
- #include
-
- int main() {
- int a = 5;
- double b = 3.14;
- double result1 = a + b; // 隐式转换
- int result2 = static_cast<int>(b); // 显式转换
-
- std::cout << "result1: " << result1 << std::endl; // 输出 8.14
- std::cout << "result2: " << result2 << std::endl; // 输出 3
- return 0;
- }
- #include
-
- class Complex {
- public:
- Complex(double r, double i) : re(r), im(i) {}
- Complex operator+(const Complex& other) const {
- return Complex(re + other.re, im + other.im);
- }
- void print() const {
- std::cout << "Complex(" << re << ", " << im << ")" << std::endl;
- }
- private:
- double re, im;
- };
-
- int main() {
- Complex a(1.0, 2.0);
- Complex b(2.0, 3.0);
- Complex c = a + b; // 使用重载的 '+' 运算符
-
- c.print(); // 输出 Complex(3.0, 5.0)
- return 0;
- }
- #include
-
- int main() {
- int a = 5;
- int b = 10;
- int c = 3;
- int result = (a + b) * c; // 使用括号改变优先级
-
- std::cout << "result: " << result << std::endl; // 输出 45
- return 0;
- }
本节总结:
提高建议:
算术运算符是最基本的运算符,用于执行基本的数学运算。C++ 提供了一组常用的算术运算符,包括加法、减法、乘法、除法和取余运算符。这些运算符的使用方法类似于我们在数学中使用它们的方式。
加法运算符用于对两个数值进行加法运算。它的操作数可以是整数或浮点数,结果类型与操作数类型一致。
- int a = 5, b = 3;
- int sum = a + b; // sum 的值为 8
-
- double x = 2.5, y = 4.0;
- double result = x + y; // result 的值为 6.5
减法运算符用于对两个数值进行减法运算。它的操作数可以是整数或浮点数,结果类型与操作数类型一致。
- int a = 5, b = 3;
- int difference = a - b; // difference 的值为 2
-
- double x = 5.5, y = 2.0;
- double result = x - y; // result 的值为 3.5
乘法运算符用于对两个数值进行乘法运算。它的操作数可以是整数或浮点数,结果类型与操作数类型一致。
- int a = 5, b = 3;
- int product = a * b; // product 的值为 15
-
- double x = 2.5, y = 4.0;
- double result = x * y; // result 的值为 10.0
除法运算符用于对两个数值进行除法运算。对于整数除法,结果是去掉小数部分的整数;对于浮点数除法,结果是包含小数部分的浮点数。
- int a = 10, b = 3;
- int quotient = a / b; // quotient 的值为 3
-
- double x = 10.0, y = 4.0;
- double result = x / y; // result 的值为 2.5
注意整数除法
在整数除法中,如果除不尽会舍弃小数部分。因此需要特别注意整数除法的结果。
- int a = 10, b = 3;
- double result = a / b; // result 的值为 3.0,而不是 3.333...
为了得到精确的浮点数结果,需要将操作数转换为浮点数类型。
- int a = 10, b = 3;
- double result = static_cast<double>(a) / b; // result 的值为 3.333...
取余运算符用于获取两个整数相除后的余数。它只能用于整数操作数。
- int a = 10, b = 3;
- int remainder = a % b; // remainder 的值为 1
使用取余运算符判断奇偶性
取余运算符可以用于判断一个数是奇数还是偶数。
- int number = 5;
- if (number % 2 == 0) {
- std::cout << "Even" << std::endl;
- } else {
- std::cout << "Odd" << std::endl;
- }
重点:
难点:
- #include
-
- int main() {
- int a = 10, b = 3;
- std::cout << "a + b = " << a + b << std::endl;
- std::cout << "a - b = " << a - b << std::endl;
- std::cout << "a * b = " << a * b << std::endl;
- std::cout << "a / b = " << a / b << std::endl;
- std::cout << "a % b = " << a % b << std::endl;
-
- return 0;
- }
- #include
-
- int main() {
- int number;
- std::cout << "Enter an integer: ";
- std::cin >> number;
-
- if (number % 2 == 0) {
- std::cout << number << " is even." << std::endl;
- } else {
- std::cout << number << " is odd." << std::endl;
- }
-
- return 0;
- }
本节总结:
提高建议:
逻辑运算符和关系运算符是C++中用于控制程序流程的重要工具。逻辑运算符用于执行布尔逻辑运算,关系运算符用于比较两个值。理解和正确使用这些运算符是编写条件判断和控制结构的基础。
关系运算符用于比较两个运算对象,返回一个布尔值true
或false
。常见的关系运算符包括:
逻辑运算符用于执行布尔逻辑运算,常见的逻辑运算符包括:
true
时,结果才为true
。true
时,结果为true
。true
变为false
,false
变为true
。
在实际编程中,关系运算符和逻辑运算符经常组合使用,以实现复杂的条件判断。
示例代码
- #include
-
- int main() {
- int x = 5, y = 10, z = 15;
-
- // 组合使用关系运算符和逻辑运算符
- if (x < y && y < z) {
- std::cout << "x < y < z" << std::endl;
- } else {
- std::cout << "Condition not met" << std::endl;
- }
-
- return 0;
- }
逻辑运算符具有短路求值的特性,即如果逻辑表达式的最终结果已经确定,则不会计算剩余部分。这在提高程序效率和避免不必要的计算方面非常有用。
示例代码
- #include
-
- bool is_positive(int n) {
- std::cout << "Checking if positive..." << std::endl;
- return n > 0;
- }
-
- int main() {
- int x = -5;
-
- // 短路求值示例
- if (x > 0 && is_positive(x)) {
- std::cout << "x is positive" << std::endl;
- } else {
- std::cout << "x is not positive" << std::endl;
- }
-
- return 0;
- }
在上面的示例中,如果x > 0
为false
,则is_positive(x)
将不会被调用,因为整个逻辑表达式的结果已经确定为false
。
重点:
难点:
- #include
-
- int main() {
- int a = 5, b = 10;
-
- std::cout << "a == b: " << (a == b) << std::endl;
- std::cout << "a != b: " << (a != b) << std::endl;
- std::cout << "a < b: " << (a < b) << std::endl;
- std::cout << "a > b: " << (a > b) << std::endl;
- std::cout << "a <= b: " << (a <= b) << std::endl;
- std::cout << "a >= b: " << (a >= b) << std::endl;
-
- return 0;
- }
- #include
-
- int main() {
- bool x = true, y = false;
-
- std::cout << "x && y: " << (x && y) << std::endl;
- std::cout << "x || y: " << (x || y) << std::endl;
- std::cout << "!x: " << (!x) << std::endl;
- std::cout << "!y: " << (!y) << std::endl;
-
- return 0;
- }
- #include
-
- int main() {
- int a = 5, b = 10, c = 15;
-
- if (a < b && b < c) {
- std::cout << "a < b < c" << std::endl;
- } else {
- std::cout << "Condition not met" << std::endl;
- }
-
- return 0;
- }
- #include
-
- bool is_positive(int n) {
- std::cout << "Checking if positive..." << std::endl;
- return n > 0;
- }
-
- int main() {
- int x = -5;
-
- if (x > 0 && is_positive(x)) {
- std::cout << "x is positive" << std::endl;
- } else {
- std::cout << "x is not positive" << std::endl;
- }
-
- return 0;
- }
本节总结:
提高建议:
赋值运算符是C++中最常用的运算符之一,用于将表达式的结果赋值给变量。赋值运算符不仅限于简单的赋值操作,还包括复合赋值运算符,用于执行赋值的同时进行其他运算。
基本赋值运算符=
用于将右侧表达式的值赋给左侧的变量。
- int a = 10;
- double b = 3.14;
- char c = 'x';
赋值运算的特点
赋值运算的结果是赋值后的左侧变量的值,并且赋值运算是从右到左进行的。
- int a, b;
- a = b = 5; // 先将5赋值给b,然后再将b的值赋给a
复合赋值运算符用于在执行赋值的同时进行其他运算,简化代码并提高可读性。常见的复合赋值运算符包括:
示例代码
- #include
-
- int main() {
- int a = 5;
-
- a += 3; // 等同于 a = a + 3
- std::cout << "a += 3: " << a << std::endl; // 输出 8
-
- a -= 2; // 等同于 a = a - 2
- std::cout << "a -= 2: " << a << std::endl; // 输出 6
-
- a *= 4; // 等同于 a = a * 4
- std::cout << "a *= 4: " << a << std::endl; // 输出 24
-
- a /= 3; // 等同于 a = a / 3
- std::cout << "a /= 3: " << a << std::endl; // 输出 8
-
- a %= 5; // 等同于 a = a % 5
- std::cout << "a %= 5: " << a << std::endl; // 输出 3
-
- return 0;
- }
由于赋值运算符的结合性是从右到左,可以连续进行多个赋值操作。
示例代码
- #include
-
- int main() {
- int a, b, c;
-
- a = b = c = 10; // 先将10赋值给c,然后将c的值赋给b,最后将b的值赋给a
- std::cout << "a: " << a << ", b: " << b << ", c: " << c << std::endl; // 输出 a: 10, b: 10, c: 10
-
- return 0;
- }
赋值运算符的返回值是赋值后的左侧变量的值,这使得赋值运算符可以嵌套在更复杂的表达式中使用。
示例代码
- #include
-
- int main() {
- int a, b;
-
- a = (b = 5) + 3; // b赋值为5,然后a赋值为b加3
- std::cout << "a: " << a << ", b: " << b << std::endl; // 输出 a: 8, b: 5
-
- return 0;
- }
重点:
难点:
- #include
-
- int main() {
- int a = 5, b = 10, c = 15;
-
- a = b = c; // 连续赋值
- std::cout << "a: " << a << ", b: " << b << ", c: " << c << std::endl; // 输出 a: 15, b: 15, c: 15
-
- a += 5; // 复合赋值
- std::cout << "a += 5: " << a << std::endl; // 输出 20
-
- b -= 3; // 复合赋值
- std::cout << "b -= 3: " << b << std::endl; // 输出 12
-
- c *= 2; // 复合赋值
- std::cout << "c *= 2: " << c << std::endl; // 输出 30
-
- return 0;
- }
- #include
-
- int main() {
- int x, y, z;
-
- x = (y = (z = 10) + 5) + 2; // 嵌套赋值
- std::cout << "x: " << x << ", y: " << y << ", z: " << z << std::endl; // 输出 x: 17, y: 15, z: 10
-
- return 0;
- }
本节总结:
提高建议:
递增(increment)和递减(decrement)运算符是C++中用于对变量进行自增和自减操作的运算符。递增运算符用于将变量的值加1,递减运算符用于将变量的值减1。递增和递减运算符既可以作为前缀使用,也可以作为后缀使用,这两种用法在具体应用中有不同的效果。
前缀递增运算符
前缀递增运算符++
在变量之前使用,它将变量的值加1,然后返回增加后的值。
++变量;
- int a = 5;
- int b = ++a; // a先加1变成6,然后b等于6
后缀递增运算符
后缀递增运算符++
在变量之后使用,它将变量的值加1,但返回的是增加前的值。
变量++;
- int a = 5;
- int b = a++; // b等于a的原值5,然后a加1变成6
前缀递减运算符
前缀递减运算符--
在变量之前使用,它将变量的值减1,然后返回减少后的值。
--变量;
- int a = 5;
- int b = --a; // a先减1变成4,然后b等于4
后缀递减运算符
后缀递减运算符--
在变量之后使用,它将变量的值减1,但返回的是减少前的值。
变量--;
- int a = 5;
- int b = a--; // b等于a的原值5,然后a减1变成4
递增和递减运算符常用于循环结构中,用于控制循环的迭代次数。此外,它们也可以用于迭代器操作,实现对容器元素的遍历。
示例代码:循环结构中的使用
- #include
-
- int main() {
- for (int i = 0; i < 5; ++i) {
- std::cout << "i: " << i << std::endl;
- }
- return 0;
- }
示例代码:迭代器操作中的使用
- #include
- #include
-
- int main() {
- std::vector<int> vec = {1, 2, 3, 4, 5};
- for (auto it = vec.begin(); it != vec.end(); ++it) {
- std::cout << *it << " ";
- }
- std::cout << std::endl;
- return 0;
- }
在使用递增和递减运算符时,需要注意它们在表达式中的副作用,尤其是在复杂表达式中可能会导致不可预期的行为。
示例代码:复杂表达式中的副作用
- #include
-
- int main() {
- int a = 5;
- int b = (a++) + (++a); // 未定义行为,a被多次修改,结果可能不一致
- std::cout << "a: " << a << ", b: " << b << std::endl;
- return 0;
- }
重点:
难点:
- #include
-
- int main() {
- int a = 5;
-
- std::cout << "Original a: " << a << std::endl;
-
- int b = ++a; // 前缀递增
- std::cout << "After prefix increment, a: " << a << ", b: " << b << std::endl;
-
- int c = a++; // 后缀递增
- std::cout << "After postfix increment, a: " << a << ", c: " << c << std::endl;
-
- return 0;
- }
- #include
-
- int main() {
- int a = 5;
-
- std::cout << "Original a: " << a << std::endl;
-
- int b = --a; // 前缀递减
- std::cout << "After prefix decrement, a: " << a << ", b: " << b << std::endl;
-
- int c = a--; // 后缀递减
- std::cout << "After postfix decrement, a: " << a << ", c: " << c << std::endl;
-
- return 0;
- }
- #include
-
- int main() {
- int counter = 0;
-
- for (int i = 0; i < 10; ++i) {
- ++counter;
- std::cout << "Counter: " << counter << std::endl;
- }
-
- return 0;
- }
- #include
-
- int main() {
- int countdown = 10;
-
- while (countdown > 0) {
- std::cout << "Countdown: " << countdown-- << std::endl;
- }
-
- std::cout << "Liftoff!" << std::endl;
-
- return 0;
- }
本节总结:
提高建议:
成员访问运算符是C++中用于访问类、结构体和联合体的成员变量和成员函数的运算符。主要包括点运算符(.
)和箭头运算符(->
)。理解成员访问运算符的使用对于操作复杂数据结构和对象至关重要。
.
)点运算符用于通过对象或结构体变量访问其成员变量或成员函数。
示例代码
- #include
-
- struct Person {
- std::string name;
- int age;
-
- void display() {
- std::cout << "Name: " << name << ", Age: " << age << std::endl;
- }
- };
-
- int main() {
- Person p;
- p.name = "John";
- p.age = 30;
-
- std::cout << "Name: " << p.name << ", Age: " << p.age << std::endl;
- p.display(); // 通过点运算符调用成员函数
-
- return 0;
- }
在这个示例中,通过对象p
使用点运算符访问其成员变量name
和age
,并调用成员函数display()
。
->
)箭头运算符用于通过指针访问对象或结构体的成员变量或成员函数。它是点运算符的简便形式,适用于指向对象的指针。
示例代码
- #include
-
- struct Person {
- std::string name;
- int age;
-
- void display() {
- std::cout << "Name: " << name << ", Age: " << age << std::endl;
- }
- };
-
- int main() {
- Person p;
- Person* ptr = &p;
-
- ptr->name = "Jane";
- ptr->age = 25;
-
- std::cout << "Name: " << ptr->name << ", Age: " << ptr->age << std::endl;
- ptr->display(); // 通过箭头运算符调用成员函数
-
- return 0;
- }
在这个示例中,通过指针ptr
使用箭头运算符访问对象p
的成员变量name
和age
,并调用成员函数display()
。
联合体(union)是一种特殊的类,其所有成员共享同一块内存。可以使用点运算符访问联合体的成员。
示例代码
- #include
-
- union Data {
- int i;
- float f;
- char str[20];
- };
-
- int main() {
- Data data;
- data.i = 10;
- std::cout << "data.i: " << data.i << std::endl;
-
- data.f = 220.5;
- std::cout << "data.f: " << data.f << std::endl;
-
- strcpy(data.str, "C++");
- std::cout << "data.str: " << data.str << std::endl;
-
- return 0;
- }
在这个示例中,通过联合体变量data
使用点运算符访问其成员变量i
、f
和str
。
重点:
难点:
- #include
-
- struct Car {
- std::string brand;
- int year;
-
- void display() {
- std::cout << "Brand: " << brand << ", Year: " << year << std::endl;
- }
- };
-
- int main() {
- Car myCar;
- myCar.brand = "Toyota";
- myCar.year = 2020;
-
- std::cout << "Brand: " << myCar.brand << ", Year: " << myCar.year << std::endl;
- myCar.display(); // 使用点运算符调用成员函数
-
- return 0;
- }
- #include
-
- struct Car {
- std::string brand;
- int year;
-
- void display() {
- std::cout << "Brand: " << brand << ", Year: " << year << std::endl;
- }
- };
-
- int main() {
- Car myCar;
- Car* ptr = &myCar;
-
- ptr->brand = "Honda";
- ptr->year = 2021;
-
- std::cout << "Brand: " << ptr->brand << ", Year: " << ptr->year << std::endl;
- ptr->display(); // 使用箭头运算符调用成员函数
-
- return 0;
- }
- #include
- #include
-
- union Data {
- int i;
- float f;
- char str[20];
- };
-
- int main() {
- Data data;
-
- data.i = 10;
- std::cout << "data.i: " << data.i << std::endl;
-
- data.f = 220.5;
- std::cout << "data.f: " << data.f << std::endl;
-
- strcpy(data.str, "C++ Primer");
- std::cout << "data.str: " << data.str << std::endl;
-
- return 0;
- }
- #include
-
- struct Node {
- int value;
- Node* next;
-
- void display() {
- std::cout << "Value: " << value << std::endl;
- }
- };
-
- int main() {
- Node node1;
- Node node2;
-
- node1.value = 10;
- node1.next = &node2;
-
- node2.value = 20;
- node2.next = nullptr;
-
- // 通过对象使用点运算符
- std::cout << "Node1 value: " << node1.value << std::endl;
- node1.display();
-
- // 通过指针使用箭头运算符
- Node* ptr = node1.next;
- std::cout << "Node2 value: " << ptr->value << std::endl;
- ptr->display();
-
- return 0;
- }
本节总结:
提高建议:
条件运算符(?:
),也称为三元运算符,是C++中唯一一个需要三个操作数的运算符。它的主要功能是简化条件表达式,使代码更加简洁。条件运算符通常用于替代简单的if-else
语句。
语法
条件运算符的基本语法如下:
condition ? expression1 : expression2;
其中,condition
是一个布尔表达式;如果condition
为true
,则返回expression1
的值,否则返回expression2
的值。
示例代码
- #include
-
- int main() {
- int a = 5, b = 10;
- int max = (a > b) ? a : b; // 如果 a 大于 b,则 max 等于 a,否则 max 等于 b
-
- std::cout << "Max: " << max << std::endl; // 输出 10
-
- return 0;
- }
在这个示例中,使用条件运算符比较a
和b
的值,并将较大者赋值给max
。
条件运算符可以嵌套使用,以处理更复杂的条件判断。不过,过度嵌套会使代码难以阅读和维护,应尽量避免。
示例代码
- #include
-
- int main() {
- int a = 5, b = 10, c = 15;
- int max = (a > b) ? (a > c ? a : c) : (b > c ? b : c);
-
- std::cout << "Max: " << max << std::endl; // 输出 15
-
- return 0;
- }
在这个示例中,嵌套的条件运算符用于找到三个数中的最大值。
条件运算符返回的结果类型取决于两个表达式的类型。如果两个表达式的类型不同,C++会进行类型转换,以确保返回值的类型一致。
示例代码
- #include
-
- int main() {
- int a = 5;
- double b = 10.5;
- auto result = (a > b) ? a : b; // 返回值的类型为 double
-
- std::cout << "Result: " << result << std::endl; // 输出 10.5
-
- return 0;
- }
在这个示例中,条件运算符返回的结果类型为double
,因为b
的类型为double
。
条件运算符可以用于简化代码,使得代码更加简洁和易读,尤其是在赋值或返回值操作中。
示例代码
- #include
- #include
-
- int main() {
- int score = 85;
- std::string grade = (score >= 60) ? "Pass" : "Fail";
-
- std::cout << "Grade: " << grade << std::endl; // 输出 Pass
-
- return 0;
- }
在这个示例中,条件运算符用于根据分数判断是否通过考试,并将结果赋值给grade
。
重点:
难点:
- #include
-
- int main() {
- int a = 5, b = 10;
- int max = (a > b) ? a : b;
-
- std::cout << "Max: " << max << std::endl; // 输出 10
-
- return 0;
- }
- #include
-
- int main() {
- int a = 5, b = 10, c = 15;
- int max = (a > b) ? (a > c ? a : c) : (b > c ? b : c);
-
- std::cout << "Max: " << max << std::endl; // 输出 15
-
- return 0;
- }
- #include
- #include
-
- int main() {
- int score;
- std::cout << "Enter your score: ";
- std::cin >> score;
-
- std::string result = (score >= 60) ? "Pass" : "Fail";
- std::cout << "Result: " << result << std::endl;
-
- return 0;
- }
- #include
-
- int main() {
- int a = 5;
- double b = 10.5;
- auto max = (a > b) ? a : b;
-
- std::cout << "Max: " << max << std::endl; // 输出 10.5
-
- return 0;
- }
本节总结:
提高建议:
位运算符用于直接操作整数类型数据的二进制位,提供了强大的低级别操作能力。C++中的位运算符包括按位与(&
)、按位或(|
)、按位异或(^
)、按位取反(~
)、左移(<<
)和右移(>>
)。这些运算符常用于嵌入式系统编程、图形处理和需要直接操作二进制数据的场景。
按位与运算符对两个整数的每一对应位进行与操作,只有当两个位都为1时结果才为1,否则为0。
示例代码
- #include
-
- int main() {
- int a = 5; // 二进制:0101
- int b = 3; // 二进制:0011
- int result = a & b; // 二进制:0001,结果:1
-
- std::cout << "a & b: " << result << std::endl; // 输出 1
- return 0;
- }
按位或运算符对两个整数的每一对应位进行或操作,只要有一个位为1,结果就为1。
示例代码
- #include
-
- int main() {
- int a = 5; // 二进制:0101
- int b = 3; // 二进制:0011
- int result = a | b; // 二进制:0111,结果:7
-
- std::cout << "a | b: " << result << std::endl; // 输出 7
- return 0;
- }
按位异或运算符对两个整数的每一对应位进行异或操作,当两个位不同,结果为1;相同,结果为0。
示例代码
- #include
-
- int main() {
- int a = 5; // 二进制:0101
- int b = 3; // 二进制:0011
- int result = a ^ b; // 二进制:0110,结果:6
-
- std::cout << "a ^ b: " << result << std::endl; // 输出 6
- return 0;
- }
按位取反运算符将一个整数的每一位都取反,即0变为1,1变为0。
示例代码
- #include
-
- int main() {
- int a = 5; // 二进制:0000000000000101
- int result = ~a; // 二进制:1111111111111010,结果:-6(在补码表示法中)
-
- std::cout << "~a: " << result << std::endl; // 输出 -6
- return 0;
- }
左移运算符将一个整数的二进制位左移指定的位数,右侧补0。
示例代码
- #include
-
- int main() {
- int a = 5; // 二进制:0101
- int result = a << 2; // 二进制:010100,结果:20
-
- std::cout << "a << 2: " << result << std::endl; // 输出 20
- return 0;
- }
右移运算符将一个整数的二进制位右移指定的位数,左侧补0(对于无符号数)或补符号位(对于有符号数)。
示例代码
- #include
-
- int main() {
- int a = 20; // 二进制:10100
- int result = a >> 2; // 二进制:101,结果:5
-
- std::cout << "a >> 2: " << result << std::endl; // 输出 5
- return 0;
- }
重点:
难点:
- #include
-
- int main() {
- int a = 5; // 二进制:0101
- int b = 3; // 二进制:0011
-
- std::cout << "a & b: " << (a & b) << std::endl; // 输出 1
- std::cout << "a | b: " << (a | b) << std::endl; // 输出 7
- std::cout << "a ^ b: " << (a ^ b) << std::endl; // 输出 6
-
- return 0;
- }
- #include
-
- int main() {
- int a = 5; // 二进制:0000000000000101
- std::cout << "~a: " << (~a) << std::endl; // 输出 -6
-
- return 0;
- }
- #include
-
- int main() {
- int a = 5; // 二进制:0101
-
- std::cout << "a << 2: " << (a << 2) << std::endl; // 输出 20
- std::cout << "a >> 2: " << (a >> 2) << std::endl; // 输出 1
-
- return 0;
- }
- #include
-
- int main() {
- int flags = 0b1010; // 位掩码:1010
- int mask = 0b0101; // 掩码:0101
-
- // 使用按位或设置位
- int set_flags = flags | mask; // 结果:1111
- std::cout << "Set flags: " << std::bitset<4>(set_flags) << std::endl; // 输出 1111
-
- // 使用按位与清除位
- int clear_flags = flags & ~mask; // 结果:1000
- std::cout << "Clear flags: " << std::bitset<4>(clear_flags) << std::endl; // 输出 1000
-
- return 0;
- }
本节总结:
提高建议:
sizeof
运算符是C++中的一个内置运算符,用于计算数据类型或对象在内存中所占的字节数。它在编译时计算结果,因此不会影响程序的运行效率。理解和使用sizeof
运算符对于内存管理和跨平台编程非常重要。
sizeof
运算符的基本用法计算基本数据类型的大小
sizeof
运算符可以用于计算基本数据类型(如int
、double
、char
等)在内存中所占的字节数。
- #include
-
- int main() {
- std::cout << "Size of int: " << sizeof(int) << " bytes" << std::endl;
- std::cout << "Size of double: " << sizeof(double) << " bytes" << std::endl;
- std::cout << "Size of char: " << sizeof(char) << " bytes" << std::endl;
- return 0;
- }
在这个示例中,sizeof
运算符用于输出int
、double
和char
类型在内存中所占的字节数。
计算变量的大小
sizeof
运算符也可以用于计算变量在内存中所占的字节数。
- #include
-
- int main() {
- int a = 10;
- double b = 3.14;
- char c = 'x';
-
- std::cout << "Size of variable a: " << sizeof(a) << " bytes" << std::endl;
- std::cout << "Size of variable b: " << sizeof(b) << " bytes" << std::endl;
- std::cout << "Size of variable c: " << sizeof(c) << " bytes" << std::endl;
- return 0;
- }
在这个示例中,sizeof
运算符用于输出变量a
、b
和c
在内存中所占的字节数。
计算数组的大小
sizeof
运算符可以用于计算数组在内存中所占的总字节数。
- #include
-
- int main() {
- int arr[10];
-
- std::cout << "Size of array arr: " << sizeof(arr) << " bytes" << std::endl;
- std::cout << "Number of elements in array arr: " << sizeof(arr) / sizeof(arr[0]) << std::endl;
- return 0;
- }
在这个示例中,sizeof
运算符用于输出数组arr
在内存中所占的总字节数,以及数组中元素的个数。
sizeof
运算符与指针sizeof
运算符可以用于计算指针的大小,但其结果与指针指向的对象无关,而是与指针本身的数据类型有关。
- #include
-
- int main() {
- int *p;
- double *q;
-
- std::cout << "Size of pointer p: " << sizeof(p) << " bytes" << std::endl;
- std::cout << "Size of pointer q: " << sizeof(q) << " bytes" << std::endl;
- return 0;
- }
在这个示例中,sizeof
运算符用于输出指针p
和q
在内存中所占的字节数。
sizeof
运算符与结构体sizeof
运算符可以用于计算结构体在内存中所占的总字节数,包括结构体成员和可能的填充字节(padding bytes)。
- #include
-
- struct Person {
- char name[50];
- int age;
- double height;
- };
-
- int main() {
- Person person;
-
- std::cout << "Size of struct Person: " << sizeof(Person) << " bytes" << std::endl;
- std::cout << "Size of variable person: " << sizeof(person) << " bytes" << std::endl;
- return 0;
- }
在这个示例中,sizeof
运算符用于输出结构体Person
的大小,以及变量person
在内存中所占的字节数。
重点:
sizeof
运算符的基本用法:掌握sizeof
运算符用于计算基本数据类型、变量、数组、指针和结构体大小的用法。sizeof
运算符与数组和结构体的应用:理解sizeof
运算符在计算数组和结构体大小中的作用,特别是计算数组元素个数和结构体填充字节。难点:
sizeof
运算符与指针的区别:初学者需要通过实践理解sizeof
运算符计算指针大小时与指针指向对象无关的特点。sizeof
运算符结果的影响。
sizeof
运算符计算其大小,并输出结果。- #include
-
- int main() {
- int a = 10;
- std::cout << "Size of int a: " << sizeof(a) << " bytes" << std::endl;
- return 0;
- }
sizeof
运算符计算其总大小和元素个数,并输出结果。- #include
-
- int main() {
- double arr[5];
-
- std::cout << "Size of array arr: " << sizeof(arr) << " bytes" << std::endl;
- std::cout << "Number of elements in array arr: " << sizeof(arr) / sizeof(arr[0]) << std::endl;
- return 0;
- }
sizeof
运算符计算其大小,并输出结果。- #include
-
- int main() {
- char *p;
- std::cout << "Size of pointer p: " << sizeof(p) << " bytes" << std::endl;
- return 0;
- }
sizeof
运算符计算其大小,并输出结果。- #include
-
- struct Car {
- char brand[20];
- int year;
- double price;
- };
-
- int main() {
- Car car;
-
- std::cout << "Size of struct Car: " << sizeof(Car) << " bytes" << std::endl;
- std::cout << "Size of variable car: " << sizeof(car) << " bytes" << std::endl;
- return 0;
- }
本节总结:
sizeof
运算符的基本用法,掌握了其用于计算基本数据类型、变量、数组、指针和结构体大小的方法。sizeof
运算符在数组和结构体中的应用,特别是计算数组元素个数和结构体填充字节的用法。sizeof
运算符与指针的区别,理解了其计算指针大小时与指针指向对象无关的特点。提高建议:
sizeof
运算符的基本操作:通过编写各种sizeof
运算操作的小程序,熟悉其用法及在不同场景中的应用。sizeof
运算符结果的影响。sizeof
运算符进行内存管理,提高代码的可移植性和运行效率。
逗号运算符(,
)是C++中的一种顺序点运算符,用于在一个语句中执行多个表达式。逗号运算符会依次计算每个表达式,并返回最后一个表达式的值。虽然逗号运算符在实际编程中不如其他运算符常用,但在特定情况下它可以简化代码,增强代码的可读性。
逗号运算符的基本语法如下:
expression1, expression2, ..., expressionN;
其中,每个表达式会依次计算,但只有最后一个表达式的值会作为整个逗号表达式的值返回。
示例代码
- #include
-
- int main() {
- int a = 1, b = 2, c = 3;
- int result = (a = a + 1, b = b + 2, c = c + 3); // 执行多个表达式,返回最后一个表达式的值
-
- std::cout << "a: " << a << ", b: " << b << ", c: " << c << ", result: " << result << std::endl;
- // 输出 a: 2, b: 4, c: 6, result: 6
-
- return 0;
- }
在这个示例中,逗号运算符用于依次计算多个表达式,result
变量的值为最后一个表达式c = c + 3
的值。
逗号运算符可以在循环控制语句中使用,例如for
循环中,可以在初始化和更新表达式中使用逗号运算符。
示例代码
- #include
-
- int main() {
- for (int i = 0, j = 10; i < j; ++i, --j) {
- std::cout << "i: " << i << ", j: " << j << std::endl;
- }
-
- return 0;
- }
在这个示例中,逗号运算符用于for
循环的初始化和更新表达式,i
从0开始递增,j
从10开始递减。
逗号运算符的返回值是最后一个表达式的值。可以将逗号运算符用于表达式中,并利用其返回值。
示例代码
- #include
-
- int main() {
- int x = 10, y = 20;
- int max = (x > y ? x : y, x + y); // 返回 x + y 的值
-
- std::cout << "max: " << max << std::endl; // 输出 30
-
- return 0;
- }
在这个示例中,逗号运算符返回最后一个表达式x + y
的值,赋值给max
变量。
逗号运算符的优先级最低,仅高于表达式的分隔符;因此,在复合表达式中使用时通常需要括号来明确表达式的求值顺序。
示例代码
- #include
-
- int main() {
- int a = 1, b = 2;
- int result = (a += 1, b += 2); // 括号确保逗号运算符的优先级
-
- std::cout << "result: " << result << std::endl; // 输出 4
-
- return 0;
- }
在这个示例中,括号确保了逗号运算符的正确计算顺序。
重点:
for
循环中的使用。难点:
- #include
-
- int main() {
- int a = 1, b = 2, c = 3;
- int result = (a += 1, b += 2, c += 3);
-
- std::cout << "a: " << a << ", b: " << b << ", c: " << c << ", result: " << result << std::endl;
- // 输出 a: 2, b: 4, c: 6, result: 6
-
- return 0;
- }
for
循环,使用逗号运算符同时更新两个变量,并输出它们的值。- #include
-
- int main() {
- for (int i = 0, j = 10; i < j; ++i, --j) {
- std::cout << "i: " << i << ", j: " << j << std::endl;
- }
-
- return 0;
- }
- #include
-
- int main() {
- int x = 5, y = 10;
- int result = (x > y ? x : y, x + y);
-
- std::cout << "result: " << result << std::endl; // 输出 15
-
- return 0;
- }
- #include
-
- int main() {
- int a = 1, b = 2, c = 3;
- int result = (std::cout << "a: " << (a += 1) << std::endl,
- std::cout << "b: " << (b += 2) << std::endl,
- std::cout << "c: " << (c += 3) << std::endl,
- c);
-
- std::cout << "Final result: " << result << std::endl; // 输出 Final result: 6
-
- return 0;
- }
本节总结:
for
循环中的使用。提高建议:
类型转换是将一种数据类型的值转换为另一种数据类型的过程。C++ 提供了多种类型转换的方法,包括隐式转换、显式转换(也称为强制转换)、C风格的转换以及 C++ 特有的类型转换运算符(static_cast
、dynamic_cast
、const_cast
和 reinterpret_cast
)。理解类型转换的机制和使用场景对于编写健壮的 C++ 程序至关重要。
隐式类型转换是由编译器自动进行的类型转换,无需显式指定。在需要不同类型的值进行运算时,编译器会自动将较小范围的类型转换为较大范围的类型,以避免数据丢失。
示例代码
- #include
-
- int main() {
- int a = 42;
- double b = 3.14;
- double result = a + b; // 隐式类型转换,将 int 类型的 a 转换为 double 类型
-
- std::cout << "result: " << result << std::endl; // 输出 45.14
- return 0;
- }
在这个示例中,int
类型的变量 a
被隐式转换为 double
类型,以便与 double
类型的变量 b
进行加法运算。
显式类型转换需要程序员明确指定类型转换,通常用于强制执行编译器不允许的类型转换。C++ 提供了多种显式类型转换的方法。
C风格的类型转换
C风格的类型转换使用括号语法。
(new_type) expression;
- #include
-
- int main() {
- double pi = 3.14;
- int int_pi = (int) pi; // C风格的类型转换
-
- std::cout << "int_pi: " << int_pi << std::endl; // 输出 3
- return 0;
- }
C++风格的类型转换
C++ 提供了四种类型转换运算符:static_cast
、dynamic_cast
、const_cast
和 reinterpret_cast
。
static_cast<new_type>(expression);
- #include
-
- int main() {
- double pi = 3.14;
- int int_pi = static_cast<int>(pi); // C++ 风格的类型转换
-
- std::cout << "int_pi: " << int_pi << std::endl; // 输出 3
- return 0;
- }
dynamic_cast<new_type>(expression);
- #include
-
- class Base {
- public:
- virtual ~Base() {}
- };
-
- class Derived : public Base {};
-
- int main() {
- Base* base_ptr = new Derived;
- Derived* derived_ptr = dynamic_cast
(base_ptr); -
- if (derived_ptr) {
- std::cout << "Conversion successful" << std::endl;
- } else {
- std::cout << "Conversion failed" << std::endl;
- }
-
- delete base_ptr;
- return 0;
- }
const
限定符。const_cast<new_type>(expression);
- #include
-
- void print(const int* p) {
- int* modifiable_p = const_cast<int*>(p);
- *modifiable_p = 10;
- std::cout << "Modified value: " << *modifiable_p << std::endl;
- }
-
- int main() {
- int a = 5;
- print(&a);
- std::cout << "a: " << a << std::endl; // 输出 10
- return 0;
- }
reinterpret_cast<new_type>(expression);
- #include
-
- int main() {
- int a = 42;
- void* void_ptr = reinterpret_cast<void*>(&a);
- int* int_ptr = reinterpret_cast<int*>(void_ptr);
-
- std::cout << "Value: " << *int_ptr << std::endl; // 输出 42
- return 0;
- }
数据丢失
在类型转换过程中,可能会发生数据丢失。例如,将浮点数转换为整数时,小数部分会被丢弃。
类型安全
使用类型转换时,应注意类型安全,避免不必要的类型转换,特别是在使用 reinterpret_cast
时,确保转换的对象是兼容的。
代码可读性
尽量使用 C++ 风格的类型转换运算符,以提高代码的可读性和安全性。
重点:
static_cast
、dynamic_cast
、const_cast
和 reinterpret_cast
的用法及其适用场景。难点:
- #include
-
- int main() {
- double pi = 3.14;
- int int_pi = static_cast<int>(pi);
-
- std::cout << "int_pi: " << int_pi << std::endl; // 输出 3
- return 0;
- }
dynamic_cast
进行安全的类型转换,并输出结果。- #include
-
- class Base {
- public:
- virtual ~Base() {}
- };
-
- class Derived : public Base {};
-
- int main() {
- Base* base_ptr = new Derived;
- Derived* derived_ptr = dynamic_cast
(base_ptr); -
- if (derived_ptr) {
- std::cout << "Conversion successful" << std::endl;
- } else {
- std::cout << "Conversion failed" << std::endl;
- }
-
- delete base_ptr;
- return 0;
- }
const_cast
去除 const
限定符,并修改指针指向的值。- #include
-
- void modify(const int* p) {
- int* modifiable_p = const_cast<int*>(p);
- *modifiable_p = 20;
- }
-
- int main() {
- int a = 10;
- modify(&a);
-
- std::cout << "a: " << a << std::endl; // 输出 20
- return 0;
- }
reinterpret_cast
将其转换为 void*
指针,再转换回整数指针,并输出结果。- #include
-
- int main() {
- int a = 42;
- void* void_ptr = reinterpret_cast<void*>(&a);
- int* int_ptr = reinterpret_cast<int*>(void_ptr);
-
- std::cout << "Value: " << *int_ptr << std::endl; // 输出 42
- return 0;
- }
本节总结:
static_cast
、dynamic_cast
、const_cast
和 reinterpret_cast
的用法及其适用场景,特别是在继承层次结构中的安全类型转换。提高建议:
reinterpret_cast
时,确保转换的对象是兼容的。
C++中的运算符有各自的优先级和结合性,运算符的优先级决定了在没有括号的情况下,表达式中各个运算符的计算顺序;结合性则决定了具有相同优先级的运算符的计算顺序。理解运算符的优先级和结合性有助于正确地编写和阅读复杂的表达式,避免意外的求值顺序导致的错误。
运算符的优先级请参考书本的P147页的4.12小节。
运算符的结合性决定了具有相同优先级的运算符的计算顺序。C++中的运算符结合性可以分为两类:
左结合运算符
常见的左结合运算符有:
+
, -
, *
, /
, %
&
, |
, ^
, <<
, >>
<
, <=
, >
, >=
==
, !=
&&
, ||
,
右结合运算符
常见的右结合运算符有:
=
, +=
, -=
, *=
, /=
, %=
, <<=
, >>=
, &=
, ^=
, |=
? :
&
!
, ~
++
, --
static_cast
, dynamic_cast
, const_cast
, reinterpret_cast
理解运算符的优先级和结合性有助于正确地编写和阅读复杂的表达式,避免意外的求值顺序导致的错误。以下是一些示例及其分析。
示例1:简单表达式
- #include
-
- int main() {
- int a = 10;
- int b = 5;
- int result = a + b * 2; // 乘法优先于加法
-
- std::cout << "result: " << result << std::endl; // 输出 20
- return 0;
- }
在这个示例中,乘法运算符的优先级高于加法运算符,因此首先计算b * 2
,然后将结果加到a
。
示例2:复合赋值运算符
- #include
-
- int main() {
- int a = 10;
- a += 5 * 2; // 乘法优先于加法赋值
-
- std::cout << "a: " << a << std::endl; // 输出 20
- return 0;
- }
在这个示例中,乘法运算符的优先级高于加法赋值运算符,因此首先计算5 * 2
,然后将结果加到a
。
示例3:混合运算符
- #include
-
- int main() {
- int a = 5;
- int b = 10;
- int c = 15;
- int result = a + b > c ? a : b; // 比较运算符优先于加法运算符,加法运算符优先于条件运算符
-
- std::cout << "result: " << result << std::endl; // 输出 10
- return 0;
- }
在这个示例中,首先计算a + b
,然后比较结果是否大于c
,最后根据条件运算符的结果返回a
或b
。
重点:
难点:
- #include
-
- int main() {
- int a = 5;
- int b = 10;
- int c = 3;
- int result = a + b * c; // 乘法优先于加法
-
- std::cout << "result: " << result << std::endl; // 输出 35
- return 0;
- }
- #include
-
- int main() {
- int a = 5;
- int b = 10;
- int c = 3;
- int result = (a + b) * c; // 使用括号改变优先级
-
- std::cout << "result: " << result << std::endl; // 输出 45
- return 0;
- }
- #include
-
- int main() {
- int a = 5;
- int b = 10;
- int c = 3;
- int result = a - b + c; // 加法和减法的结合性是从左到右
-
- std::cout << "result: " << result << std::endl; // 输出 -2
- return 0;
- }
- #include
-
- int main() {
- int a = 5;
- int b = 10;
- int c = 3;
- int result = (a > b ? a : b) + c; // 条件运算符优先级低于加法运算符
-
- std::cout << "result: " << result << std::endl; // 输出 13
- return 0;
- }
本节总结:
提高建议:
本主页会定期更新,为了能够及时获得更新,敬请关注我:点击左下角的关注。也可以关注公众号:请在微信上搜索公众号“iShare爱分享”并关注,或者扫描以下公众号二维码关注,以便在内容更新时直接向您推送。