C++ 知识量:19 - 82 - 316
C++中的运算符包括算术运算符、比较运算符、逻辑运算符、位运算符、赋值运算符、条件运算符、逗号运算符、sizeof运算符、类型转换运算符、赋值运算符等等。
算术运算符:用于进行基本的算术运算,包括加法、减法、乘法、除法、取模等。
比较运算符:用于比较两个值的大小关系,包括等于、不等于、大于、小于等。
逻辑运算符:用于进行逻辑运算,包括与、或、非等。
位运算符:用于对二进制位进行操作,包括按位与、按位或、按位异或等。
赋值运算符:用于将右侧的值赋给左侧的变量,包括等于、加等于、减等于、乘等于等。
条件运算符:用于进行条件判断,例如三目运算符。
逗号运算符:用于将多个表达式连接在一起,例如逗号表达式。
sizeof运算符:用于获取变量或类型的大小,例如sizeof(int)。
类型转换运算符:用于将一种类型转换为另一种类型,例如static_cast<int>(2.5)。
除了上述常见的运算符外,C++还支持自定义运算符,例如重载运算符。通过重载运算符,可以定义自己的运算符行为,以满足特定的需求。
C++中运算符的优先级如下:
括号(( ))具有最高优先级。
成员访问运算符(.``)和箭头运算符(->`)具有相同的优先级,比下一级运算符优先级高。
算术运算符(+ - * / %)具有相同的优先级,比下一级运算符优先级高。
移位运算符(<< >>)具有相同的优先级,比下一级运算符优先级高。
关系运算符(< <= > >=)具有相同的优先级,比下一级运算符优先级高。
等于运算符(==)具有相同的优先级,比下一级运算符优先级高。
不等于运算符(!=)具有相同的优先级,比下一级运算符优先级高。
位与运算符(&)具有相同的优先级,比下一级运算符优先级高。
位异或运算符(^)具有相同的优先级,比下一级运算符优先级高。
位或运算符(|)具有相同的优先级,比下一级运算符优先级高。
逻辑与运算符(&&)具有相同的优先级,比下一级运算符优先级高。
逻辑或运算符(||)具有相同的优先级,比下一级运算符优先级高。
条件运算符(? :)具有相同的优先级,比下一级运算符优先级高。
赋值运算符(= += -= *= /= %= >>= <<= &= ^= |=)具有相同的优先级,比下一级运算符优先级高。
逗号运算符(,)具有最低的优先级。
在C++中,大多数运算符都是符合结合律的。结合律意味着当一个操作数有多个运算符时,运算符的优先级和结合方向不会影响运算结果。
例如,考虑以下表达式:
3 + 4 * 5
根据C++的运算符优先级和结合律,这个表达式的计算结果是23。尽管乘法运算符的优先级高于加法运算符,但结合律保证了先执行乘法运算,然后再执行加法运算。
但是,有些运算符是不符合结合律的。例如,逻辑运算符&&和||。当一个表达式中有多个逻辑运算符时,它们的结合方向会直接影响运算结果。
例如,考虑以下表达式:
true && false || true
由于&&运算符的优先级高于||运算符,因此首先会执行&&运算。然后,由于&&运算符的左侧为false,因此整个&&表达式的结果为false。接下来,由于||运算符的左侧为false,因此整个||表达式的结果为true。因此,整个表达式的计算结果是true。
需要注意的是,C++中的逻辑运算符&&和||都是短路运算符。这意味着在计算逻辑表达式时,如果已经可以确定整个逻辑表达式的结果,那么后续的运算将不会被执行。这可以帮助优化程序的性能。
在C++中,表达式的求值顺序主要遵循以下规则:
括号内的运算总是比括号外的运算先执行。
同一优先级的运算符按照从左到右的顺序执行。
不同优先级的运算符按照优先级从高到低的顺序执行。
同一优先级的运算符,如果结合方向是从左到右,则按照从左到右的顺序执行;如果结合方向是从右到左,则按照从右到左的顺序执行。
例如,考虑以下表达式:
a + b * c + d % e / f % g
在这个表达式中,有四个乘法运算符、一个加法运算符、一个模运算符和一个除法运算符。根据上述规则,这个表达式的求值顺序如下:
首先,括号内的运算先执行。在这个表达式中,没有括号,所以不需要考虑这一步。
然后,执行乘法运算。根据结合方向从左到右的原则,先执行b * c,得到结果bc。然后执行a + bc,得到结果abc。
接下来,执行模运算。根据结合方向从左到右的原则,先执行d % e,得到结果de。然后执行abc + de,得到结果abcde。
最后,执行除法运算。根据结合方向从左到右的原则,先执行f / g,得到结果fg。然后执行abcde / fg,得到最终结果abcde/fg。
需要注意的是,C++中的算术运算符(如+、-、*、/和%)都是短路运算符。这意味着在计算表达式时,如果运算符的左侧表达式的结果已经可以确定整个表达式的结果,那么右侧表达式将不会被执行。这可以帮助优化程序的性能。
在C++中,有些运算符可以用于不同类型的对象。在这些情况下,C++会尝试进行一种叫做"类型提升"的转换,将运算对象转换为适当的类型以便进行运算。这种转换可能包括将较低精度的类型(如char或short)转换为较高精度的类型(如int或long),或者将非整数类型转换为整数类型。
然而,这种自动类型提升可能会导致一些意想不到的结果,特别是在涉及浮点数和整数转换时。例如,将浮点数转换为整数通常采用"向下取整"的方式,也就是说会丢弃小数部分。
如果想对两个不同类型的对象执行运算,并且希望结果具有特定的精度,需要明确地进行类型转换。C++提供了几种类型转换运算符,包括static_cast、dynamic_cast、const_cast和reinterpret_cast。这些运算符的使用取决于具体需求。
例如,如果想将一个浮点数转换为整数,可以使用静态转换(static_cast):
float f = 3.14; int i = static_cast<int>(f); // i现在是3,小数部分被丢弃
如果想将一个整数转换为浮点数,也可以使用静态转换:
int i = 3; float f = static_cast<float>(i); // f现在是3.0
C++允许程序员重载(或自定义)运算符,以改变它们的行为。重载的运算符可以用于类定义中,以实现类的特定行为。以下是如何在C++中重载运算符的基本步骤:
声明运算符函数:运算符重载函数必须被声明为成员函数或者友元函数。它不能是全局函数,因为全局函数可能会与类中的其他成员函数产生冲突。
定义运算符重载函数:运算符重载函数的定义应该符合其原始形式,但是可以带有额外的参数。例如,如果想重载加号运算符,函数可能看起来像这样:返回_type operator+(const Type& other)。
返回类型:运算符重载函数的返回类型应该符合预期。例如,加法运算符的返回类型可能是想相加的两个对象的类型。
参数:运算符重载函数可以有一个或多个参数。例如,加法运算符可能接受两个参数。
调用顺序:运算符重载函数的调用顺序应该符合预期。例如,加法运算符应该先调用一个对象的成员函数,然后再调用另一个对象的成员函数。
下面是一个简单的例子,展示了如何在C++中重载加号运算符:
class Complex { public: Complex(double real = 0.0, double imag = 0.0): m_real(real), m_imag(imag) {} // 重载加法运算符 Complex operator+(const Complex& b) const { return Complex(m_real + b.m_real, m_imag + b.m_imag); } private: double m_real; double m_imag; };
在这个例子中,创建了一个名为Complex的类,它代表了一个复数。重载了加号运算符,因此可以将两个Complex对象相加。
在C++中,表达式可以被分为左值和右值。这种分类基于表达式是否可以独立存在。
1. 左值(Lvalue):左值是可以被赋值的表达式的统称。简单来说,左值是指向可寻址的对象的表达式。例如,变量、数组元素或结构体成员等。这些表达式可以出现在赋值语句的左边,表示一个可以存储值的实体。
例如:
int a = 10; // 'a'是一个左值,因为它是一个可寻址的变量,可以被赋值。
2. 右值(Rvalue):右值是不能独立存在的表达式的统称。这些表达式通常出现在赋值语句的右边,表示一个临时的、不能存储值的实体。例如,常量、字面量或临时对象等。
例如:
10 + a; // '10'是一个右值,因为它是一个常量,不能被赋值。
在C++中,右值引用是C++11引入的一个重要特性,允许开发者利用右值进行优化,例如移动语义和完美转发等。通过右值引用,可以将临时对象(右值)的资源“移动”到另一个对象(左值)中,从而提高代码效率。
Copyright © 2017-Now pnotes.cn. All Rights Reserved.
编程学习笔记 保留所有权利
MARK:3.0.0.20240214.P35
From 2017.2.6