其它常用运算符

最后我们列举一些其它我们现在需要掌握得其它运算符。实际上,还有许多其它的运算符我们尚未学习。

条件运算符

条件运算符可以在表达式内部形成一个分支结构。

运算符名称作用
a ? b : c条件运算符形成分支结构

条件表达式是唯一的三元(三目)表达式。它的写法如下:

操作数1 ? 操作数2 : 操作数3

这个表达式的求值也比较形象。若“操作数1”为 true (或能隐式转换为 true ),则对“操作数2”求值并以“操作数2”的值为整个表达式的值。反之,若“操作数1”为 false (或能隐式转换为 false ),则对“操作数3”求值并以“操作数3”的值为整个表达式的值。

我们可以用 if - else 结构进行类比。例如:

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

相当于:

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

优先级和结合方向

条件运算符的优先级与赋值运算符相同。由于条件运算符的三元特殊性,故 ?: 中间的操作数如同视有括号,不考虑优先级。

条件运算符的结合方向为从右向左。 **

逗号运算符

逗号运算符并不进行实际的运算,它的主要作用是先后求值两个表达式。

运算符名称作用
a, b逗号运算符求左侧操作数,然后求右侧操作数

逗号表达式的写法:

左侧操作数, 右侧操作数

这里的操作数一般是表达式。当求逗号表达式的值的时候,会求左侧操作数的值并抛弃求右侧操作数的值。最终将右侧操作数的值作为整个逗号表达式的值

举个例子:

x = (a = 3, 42 + 1);

这里的 a = 3, 42 + 1 就是逗号表达式。正如上所述,先求左侧操作数 a = 3 的值,将 a 赋值为 3 并求得值为 3 (但是这个值会被抛弃掉)。然后求右侧操作数 42 + 1 的值为 43 。因此整个表达式的值就是 43 。 逗号表达式在循环语句中有一些用处。比如:

char c;
while (cin >> c, c != 'm') {
    // some code
}

这里的循环条件先读取一个用户输入,然后判断用户输入是否等于 'm' 。这样可以一定程度上让程序代码变得简洁。如果你没有理解这个例子也没有关系,它并不重要。

优先级和结合方向

逗号运算符的优先级在 C++ 中最低。 逗号运算符的结合方向为从左向右。这意味着你可以写这样的表达式:

expr1, expr2, expr3, ..., exprn

它将从左向右求 expr1 , expr2 …… exprn 的值,并以 exprn 的值为整个表达式的值。

类型转换运算符

在 C++ 中,类型转换也相当复杂。不过不用担心,我们目前先学习较为简单的 C 风格类型转换。

运算符名称作用
(type)aC 风格转型运算符a转换为 type 类型
type(a)函数式转型运算符

表达式写法:

(类型标识)操作数
类型标识(操作数)

表达式的值就是转换为由 类型标识 指定的新类型的 操作数 的值。对于简单的类型,类型标识 就是之前说的类型标识符,如 int unsigned double long long 等等。

例如:

int a{42};
float x{1.0f}, y{2.0f};
// 以下是类型转换表达式
(double)a;
int(x + y);
float(5 / 3);

这三个表达式的值分别为 double 类型的 42.0int 类型的 3float 类型的 1.0 (想一想,为什么不是 1.666... ?)。

请注意,类型转换并不改变操作数的类型,而是根据操作数的生成一个新类型的值。这里再次重申:在 C++ 中,一个已经声明并定义的变量的类型不会发生改变

C 风格类型转换会尝试执行以下两种操作:

  1. 进行与隐式转换相同规则的转换( static_cast )。规则可参见隐式转换章节。
  2. 进行指针重解释转换( reinterpret_cast ),即转换指针的基类型。该操作被认为是有风险的。

C 风格类型转换也可以同时移除变量只读性(通过指向只读变量的指针或者只读变量的引用)( const_cast )。该操作也被认为是有风险的。

类型转换表达式将要转换的类型明确地体现在代码中,因此这种类型转换成为显式类型转换(explicit cast)。而在 C++ 中类型转换有时又会自动发生(无需手动通过类型转换表达式发生),这些类型转换就是稍后我们会了解到的隐式类型转换。

优先级和结合方向

  • C 风格转型运算符的优先级与前缀自增/减运算符相同,高于算术运算符。其结合方向为从右向左。
  • 函数式转型运算符的优先级与后缀自增/减运算符相同。其结合方向为从左向右。函数式转型要求类型标识中不含空格、 &*

可以使用 usingtypedef 为类型指定别名来绕开此限制。

sizeof 运算符

sizeof 运算符用于查看一个操作数的类型所占的存储空间字节数。

运算符名称作用
sizeof(a)sizeof 运算符查看 a 这个类型或值所占用的内存大小

sizeof 表达式的写法有两种,既可以直接写类型标识,也可以写一个操作数(变量、字面量或表达式):

sizeof(类型标识)
sizeof 操作数

比如:

sizeof(int);
sizeof(42);
sizeof(char);
sizeof('@');
sizeof(long long);
sizeof(1000000000000ll);
// int[10] 是指拥有 10 个 int 的数组类型,如 `int a[10]{};` 中 a 的类型
sizeof(int[10]);

上述表达式的可能值分别为 4 , 4 , 1 , 1 , 8 , 8 , 40 。对于一个类型,这是这种类型的一个变量所占存储空间的字节数;对于一个操作数来说,这是存储这个操作数所需要的的存储空间的字节数。

sizeof 表达式的值在编译期间就会被确定,因此 sizeof 表达式无例外地都是常量

这也侧面指出数组的长度必须是常量,否则数组类型 sizeof 表达式的值就不是常量了。

sizeof 表达式的值的类型为 std::size_t 。在某些编译器下,这个类型与 unsigned int 等价。

优先级和结合方向

sizeof 运算符的优先级和前缀自增/减运算符相同。其结合性为从右向左。

尽管 sizeof 运算符查看操作数大小时不需要加括号,但建议加上括号以防止歧义。

sizeof (int) * p 这个表达式是有歧义的。

最近更新:
代码未运行