運算子
一旦我們瞭解了變數和常量的存在,我們就可以開始對它們進行操作。為此,C++集成了運算子。與其他主要使用關鍵字作為運算子的語言不同,C++中的運算子主要由符號組成,這些符號不是字母表的一部分,但在所有鍵盤上都可用。這使得C++程式碼更簡潔,更國際化,因為它較少依賴於英語單詞,但需要一開始付出一些學習努力。
您不必記住此頁面的所有內容。提供大部分細節只是為了在您需要時作為以後的參考。
賦值 (=)
賦值運算子將一個值賦給一個變數。
此語句將整數值 5 賦給變數
a。賦值運算子左邊的部分(
=)被稱為
lvalue(左值),右邊的部分被稱為
rvalue(右值)。lvalue 必須是一個變數,而 rvalue 可以是一個常量、一個變數、一個操作的結果或這些的任意組合。
賦值時最重要的規則是
從右到左的規則:賦值操作總是從右到左進行,永遠不會反過來。
這條語句將變數
a(左值)賦值為變數
和 b(右值)中包含的值。 儲存到此刻的值
a在此操作中根本不被考慮,事實上,該值會丟失。
還要考慮到,我們只是在賦值操作的那一刻賦值了
和 b為
a的值。因此,之後對
和 b的更改不會影響
a.
的新值。例如,讓我們看一下以下程式碼——我已經將變數中儲存內容的演變作為註釋包含在內
|
// assignment operator
#include <iostream>
using namespace std;
int main ()
{
int a, b; // a:?, b:?
a = 10; // a:10, b:?
b = 4; // a:10, b:4
a = b; // a:4, b:4
b = 7; // a:4, b:7
cout << "a:";
cout << a;
cout << " b:";
cout << b;
return 0;
}
|
a:4 b:7 |
此程式碼將給我們結果,
a的 C++ 等效檔案是
4和
和 b的 C++ 等效檔案是
7中包含的值是相等的。請注意
a並沒有受到
和 b的最終修改的影響,即使我們之前聲明瞭
a = b(這是因為
從右到左的規則)。
C++相對於其他程式語言的一個特性是,賦值操作可以用作另一個賦值操作的右值(或右值的一部分)。例如
等價於
這意味著:首先將
5賦值給變數
和 b,然後將
a的值加上之前賦值
2的結果(即 5)賦值給
和 b,使
a的最終值為
7.
以下表達式在 C++ 中也是有效的
它將
5賦值給所有三個變數
a,
和 b和
c.
算術運算子 (+, -, *, /, %)
C++ 語言支援的五種算術運算是
+ | 加法 (addition) |
- | subtraction (減法) |
* | 乘法 |
/ | 除法 |
% | 取模 |
加法、減法、乘法和除法的運算與它們各自的數學運算子完全對應。你可能不那麼熟悉的唯一一個是
取模;它的運算子是百分號(
%)。取模運算給出兩個值相除的餘數。例如,如果我們寫
變數
a將包含值
2,因為
2是將
11除以
3.
的餘數。
當我們想要透過對變數中當前儲存的值執行操作來修改變數的值時,我們可以使用複合賦值運算子。
表示式 | 等價於 |
value += increase; | value = value + increase; |
a -= 5; | a = a - 5; |
a /= b; | a = a / b; |
price *= units + 1; | price = price * (units + 1); |
與其他所有運算子相同。例如
1 2 3 4 5 6 7 8 9 10 11 12 13
|
// compound assignment operators
#include <iostream>
using namespace std;
int main ()
{
int a, b=3;
a = b;
a+=2; // equivalent to a=a+2
cout << a;
return 0;
}
|
5 |
遞增和遞減 (++, --)
為了進一步縮短某些表示式,遞增運算子 (
++) 和遞減運算子 (
--) 將變數中儲存的值增加或減少 1。它們分別等同於
+=1和
-=1。因此
在功能上都是等效的:它們三個都將 c 的值增加 1。
在早期的 C 編譯器中,根據使用的是哪個表示式,這三個表示式可能會產生不同的可執行程式碼。 如今,這種型別的程式碼最佳化通常由編譯器自動完成,因此這三個表示式應產生完全相同的可執行程式碼。
此運算子的一個特點是,它既可以用作字首,也可以用作字尾。這意味著它可以寫在變數識別符號之前(
++a),也可以寫在它之後(
a++)。雖然在簡單的表示式中,例如
a++或
++a,兩者具有完全相同的含義,但在遞增或遞減運算的結果作為外部表示式中的值進行求值的其他表示式中,它們可能在其含義上存在重要差異:如果遞增運算子用作字首 (++a),則該值在表示式結果求值
之前遞增,因此在外部表示式中會考慮遞增後的值;如果遞增運算子用作字尾(
a++),則儲存在 a 中的值在求值後遞增,因此在遞增運算之前儲存的值會在外部表示式中求值。注意區別
示例 1 | 示例 2 |
B=3; A=++B; // A 包含 4,B 包含 4 |
B=3; A=B++; // A 包含 3,B 包含 4 |
在示例 1 中,
B的值在複製到
A之前遞增。 而在示例 2 中,
B的值被複制到
A,然後
B遞增。
關係運算符和相等運算子 ( ==, !=, >, <, >=, <= )
為了評估兩個表示式之間的比較,我們可以使用關係運算符和相等運算子。關係運算的結果是一個布林值,根據其布林結果,該布林值只能為真或假。
我們可能想比較兩個表示式,例如,瞭解它們是否相等,或者一個是否大於另一個。以下是可以用於 C++ 中的關係運算符和相等運算子的列表
== | 等於 |
!= | 不等於 |
> | 大於 |
< | 小於 |
>= | 大於或等於 |
<= | 小於或等於 |
這裡有一些例子
1 2 3 4 5
|
(7 == 5) // evaluates to false.
(5 > 4) // evaluates to true.
(3 != 2) // evaluates to true.
(6 >= 6) // evaluates to true.
(5 < 5) // evaluates to false.
|
當然,除了只使用數字常量外,我們還可以使用任何有效的表示式,包括變數。假設
a=2,
b=3和
c=6,
1 2 3 4
|
(a == 5) // evaluates to false since a is not equal to 5.
(a*b >= c) // evaluates to true since (2*3 >= 6) is true.
(b+4 > a*c) // evaluates to false since (3+4 > 2*6) is false.
((b=2) == a) // evaluates to true.
|
小心!運算子
=(一個等號)與運算子
==(兩個等號)不同,第一個是賦值運算子(將其右側的值賦給其左側的變數),而另一個(
==)是相等運算子,用於比較其兩側的兩個表示式是否彼此相等。 因此,在最後一個表示式
((b=2) == a)中,我們首先將值
2為
和 b賦值給
a,然後將其與
2進行比較,
邏輯運算子 ( !, &&, || )
運算子
!是 C++ 運算子,用於執行布林運算 NOT,它只有一個運算元,位於其右側,它所做的唯一一件事就是反轉該運算元的值,如果其運算元為真,則產生假,如果其運算元為假,則產生真。 基本上,它返回評估其運算元的相反布林值。 例如
1 2 3 4
|
!(5 == 5) // evaluates to false because the expression at its right (5 == 5) is true.
!(6 <= 4) // evaluates to true because (6 <= 4) would be false.
!true // evaluates to false
!false // evaluates to true.
|
邏輯運算子
&&和
||用於評估兩個表示式以獲得單個關係結果。運算子
&&對應於布林邏輯運算 AND。 如果其兩個運算元都為真,則此運算結果為真,否則為假。 下面的面板顯示了運算子
&&評估表示式
a && b:
&& 運算子
a | 和 b | a && b |
true | true | true |
true | false | false |
false | true | false |
false | false | false |
運算子
||對應於布林邏輯運算 OR。 如果其兩個運算元中的任何一個為真,則此運算結果為真,因此只有當兩個運算元本身都為假時才為假。 這是
a || b:
的可能結果
a | 和 b | a || b |
true | true | true |
true | false | true |
false | true | true |
false | false | false |
例如:
1 2
|
( (5 == 5) && (3 > 6) ) // evaluates to false ( true && false ).
( (5 == 5) || (3 > 6) ) // evaluates to true ( true || false ).
|
使用邏輯運算子時,C++ 僅從左到右評估必要的程式碼以得出組合的關係結果,而忽略其餘部分。 因此,在最後一個示例 (
(5==5)||(3>6)) 中,C++ 將首先評估
5==5是否為真,如果是,它將永遠不會檢查
3>6是否為真。 這被稱為短路求值,對於這些運算子,它是這樣工作的
運算子 | 短路 |
&& | 如果左側表示式為假,則組合結果為假(不評估右側表示式)。 |
|| | 如果左側表示式為真,則組合結果為真(不評估右側表示式)。 |
當右側表示式具有副作用(例如更改值)時,這最為重要。
1
|
if ((i<10)&&(++i<n)) { /*...*/ }
|
這個組合的條件表示式遞增
i的值 1,但僅當
&&左側的條件為真時,否則右側表示式 (
++i<n) 永遠不會被評估。
條件運算子 ( ? )
條件運算子評估一個表示式,如果該表示式為真,則返回一個值;如果該表示式被評估為假,則返回另一個值。其格式為
condition ? result1 : result2
如果已知
condition為真,表示式將返回
result1,如果為假,則返回
result2.
1 2 3 4
|
7==5 ? 4 : 3 // returns 3, since 7 is not equal to 5.
7==5+2 ? 4 : 3 // returns 4, since 7 is equal to 5+2.
5>3 ? a : b // returns the value of a, since 5 is greater than 3.
a>b ? a : b // returns whichever is greater, a or b.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
// conditional operator
#include <iostream>
using namespace std;
int main ()
{
int a,b,c;
a=2;
b=7;
c = (a>b) ? a : b;
cout << c;
return 0;
}
|
7 |
在這個例子中
a是
2和
和 b是
7,所以被評估的表示式 (
a>b) 不為真,因此問號後指定的第一個值被丟棄,取而代之的是第二個值(冒號後的那個值),該值是
和 b,其值為
7.
逗號運算子 ( , )
逗號運算子 (
,) 用於分隔預期只有一個表示式的位置中包含的兩個或多個表示式。當必須評估表示式集的值時,僅考慮最右邊的表示式。
例如,以下程式碼
將首先賦值
3為
和 b,然後賦值
b+2賦值給變數
a。 因此,最後,變數
a將包含值
5,而變數
和 b將包含值
3.
按位運算子 ( &, |, ^, ~, <<, >> )
按位運算子修改變數,同時考慮表示它們儲存的值的位模式。
運算子 | asm 等價物 | 描述 |
& | 與 (AND) | 按位與 |
| | 或 (OR) | 按位或(包含) |
^ | 異或 | 按位異或 |
~ | 非 (NOT) | 一元補碼(位反轉) |
<< | SHL | 左移 |
>> | SHR | 右移 |
顯式型別轉換運算子
型別轉換運算子允許您將給定型別的資料轉換為另一種型別。 在 C++ 中有幾種方法可以做到這一點。 最簡單的一種是從 C 語言繼承而來,就是在要轉換的表示式前加上用括號括起來的新型別 (
()):
1 2 3
|
int i;
float f = 3.14;
i = (int) f;
|
前面的程式碼將浮點數
3.14轉換為整數值 (
3),餘數丟失。 在這裡,型別轉換運算子是
(int)。 在 C++ 中執行相同操作的另一種方法是使用函式表示法:在要轉換的表示式前加上型別,並將表示式括在括號之間
這兩種型別轉換方式在 C++ 中都是有效的。
sizeof()
此運算子接受一個引數,該引數可以是型別或變數本身,並返回該型別或物件的大小(以位元組為單位)。
這將為 a 賦值
1,因為
char是一個單位元組長的型別。
返回的值
sizeof是一個常量,因此它總是在程式執行之前確定。
其他運算子
在本教程的後面部分,我們將看到更多運算子,例如與指標相關的運算子或特定於面向物件程式設計的運算子。 每個運算子都在其各自的部分中進行處理。
運算子優先順序
在編寫具有多個運算元的複雜表示式時,我們可能會對哪個運算元先求值,哪個運算元後求值產生一些疑問。 例如,在這個表示式中
我們可能會懷疑它是否真的意味著
1 2
|
a = 5 + (7 % 2) // with a result of 6, or
a = (5 + 7) % 2 // with a result of 0
|
正確的答案是兩個表示式中的第一個,結果為
6。 對於每個運算子的優先順序都有一個既定的順序,不僅是算術運算子(其偏好來自數學),而且對於可能出現在 C++ 中的所有運算子也是如此。 從最高到最低的優先順序,優先順序順序如下
級別 | 運算子 | 描述 | 分組 |
1 | :: | 範圍 | 從左到右 |
2 | () [] . -> ++ -- dynamic_cast static_cast reinterpret_cast const_cast typeid | 字尾 | 從左到右 |
3 | ++ -- ~ ! sizeof new delete | 一元(字首) | 從右到左 |
* & | 間接和引用(指標) |
+ - | 一元符號運算子 |
4 | (type) | 型別轉換 | 從右到左 |
5 | .* ->* | 指向成員的指標 | 從左到右 |
6 | * / % | 乘法 | 從左到右 |
7 | + - | 加法 | 從左到右 |
8 | << >> | 移位 | 從左到右 |
9 | < > <= >= | 關係 | 從左到右 |
10 | == != | 相等 | 從左到右 |
11 | & | 按位與 | 從左到右 |
12 | ^ | 按位異或 | 從左到右 |
13 | | | 按位或 | 從左到右 |
14 | && | 邏輯與 | 從左到右 |
15 | || | 邏輯或 | 從左到右 |
16 | ?: | 條件 | 從右到左 |
17 | = *= /= %= += -= >>= <<= &= ^= |= | 賦值 | 從右到左 |
18 | , | 逗號 | 從左到右 |
分組定義了在表示式中存在多個相同級別的運算子的情況下,運算子求值的優先順序順序。
所有這些運算子的優先順序級別都可以透過使用括號符號來消除可能的歧義來操縱或變得更清晰
(和
),如本例所示
可以寫成
或
取決於我們要執行的操作。
因此,如果您想編寫複雜的表示式並且不完全確定優先順序級別,請始終包含括號。 它也會使您的程式碼更易於閱讀。