Bài này được xây dựng dựa trên các khái niệm từ bài – Giới thiệu về các ký tự và toán tử.

Trong toán học, một phép toán là một phép tính toán học liên quan đến không hoặc nhiều giá trị đầu vào (gọi là toán hạng) tạo ra một giá trị mới (gọi là giá trị đầu ra). Hoạt động cụ thể được thực hiện được biểu thị bằng một cấu trúc (thường là một ký hiệu hoặc một cặp ký hiệu) được gọi là một toán tử.

Ví dụ, khi còn nhỏ, tất cả chúng ta đều học rằng 2 + 3 bằng 5. Trong trường hợp này, chữ 2 và 3 là toán hạng và ký hiệu + là toán tử yêu cầu chúng ta áp dụng phép cộng toán học trên các toán hạng để tạo ra giá trị mới 5.

Trong bài này, cafedev sẽ thảo luận về các chủ đề liên quan đến toán tử và khám phá nhiều toán tử phổ biến mà C ++ hỗ trợ.

1. Độ ưu tiên toán tử

Bây giờ, hãy xem xét một biểu thức phức tạp hơn, chẳng hạn như 4 + 2 * 3. Để đánh giá biểu thức này, chúng ta phải hiểu cả những gì các toán tử làm và thứ tự chính xác để áp dụng chúng. Thứ tự mà các toán tử được đánh giá trong một biểu thức ghép được xác định bởi mức độ ưu tiên của toán tử. Sử dụng các quy tắc ưu tiên toán học thông thường (cho biết rằng phép nhân được giải quyết trước khi cộng), chúng ta biết rằng biểu thức trên phải đánh giá là 4 + (2 * 3) để tạo ra giá trị 10.

Trong C ++, khi trình biên dịch gặp một biểu thức, nó cũng phải phân tích biểu thức đó và xác định cách đánh giá biểu thức đó. Để hỗ trợ điều này, tất cả các toán tử được chỉ định một mức độ ưu tiên. 

Các toán tử có mức độ ưu tiên cao nhất được đánh giá đầu tiên.

Bạn có thể thấy trong bảng bên dưới rằng phép nhân và phép chia (mức độ ưu tiên 5) được ưu tiên hơn so với phép cộng và phép trừ (mức độ ưu tiên 6). Do đó, 4 + 2 * 3 đánh giá là 4 + (2 * 3) vì phép nhân có mức độ ưu tiên cao hơn phép cộng.

2. Sự liên kết của toán tử

Điều gì xảy ra nếu hai toán tử trong cùng một biểu thức có cùng mức ưu tiên? Ví dụ: trong biểu thức 3 * 4/2, các toán tử nhân và chia đều là mức ưu tiên 5. Trong trường hợp này, trình biên dịch không thể chỉ dựa vào mức độ ưu tiên để xác định cách đánh giá kết quả.

Nếu hai toán tử có cùng mức độ ưu tiên nằm liền kề nhau trong một biểu thức, thì tính liên kết của toán tử sẽ cho trình biên dịch biết nên đánh giá các toán tử từ trái sang phải hay từ phải sang trái. Các toán tử ở mức độ ưu tiên 5 có sự kết hợp từ trái sang phải, do đó, biểu thức được phân giải từ trái sang phải: (3 * 4) / 2 = 6.

3. Bảng toán tử

Bảng dưới đây chủ yếu là một biểu đồ tham chiếu mà bạn có thể tham khảo lại trong tương lai để giải quyết bất kỳ câu hỏi liên quan hoặc ưu tiên nào bạn có.

Ghi chú:

Mức độ ưu tiên 1 là mức độ ưu tiên cao nhất và mức độ 17 là mức độ ưu tiên thấp nhất. Các toán tử có mức ưu tiên cao hơn sẽ được đánh giá trước.

L-> R có nghĩa là sự kết hợp từ trái sang phải.

R-> L có nghĩa là sự kết hợp từ phải sang trái.

Độ ưu tiên và thứ tựToán tửMôt tảcông thức chung để dùng
1 None::::Phạm vi toàn cầu (một lần)Phạm vi không gian tên (nhị phân)::nameclass_name::member_name
2 L->R()()(){}type()type{}[].
->++––typeid
const_castdynamic_castreinterpret_caststatic_castsizeof…noexceptalignof
Dấu ngoặc đơnGọi hàmKhởi tạoKhởi tạo thống nhất (C ++ 11)Hàm Chuyển đổiTruyền hàm  (C ++ 11)Chỉ số mảngQuyền truy cập thành viên từ đối tượngQuyền truy cập thành viên từ đối tượng ptrTăng sauHậu giảmThông tin kiểu trong thời gian chạyChuyển đổi  constChuyển đổi kiểu kiểm tra thời gian chạyChuyển đổi kiểu này sang kiểu khácBiên dịch kiểu kiểm tra kiểu thời gianNhận kích thước gói thông sốKiểm tra ngoại lệ thời gian biên dịchNhận căn chỉnh loại(biểu thức)function_name(parameters)type name(biểu thức)type name{biểu thức}new_type(biểu thức)new_type{biểu thức}pointer[biểu thức]object.member_nameobject_pointer->member_namelvalue++lvalue––typeid(type) or typeid(biểu thức)const_cast<type>(biểu thức)dynamic_cast<type>(biểu thức)reinterpret_cast<type>(biểu thức)static_cast<type>(biểu thức)sizeof…(biểu thức)noexcept(biểu thức)alignof(Type)
3 R->L+-++––!~(type)sizeofco_await&*newnew[]deletedelete[]Cộng một lầnTrừ một bậcTăng trướcGiảm trướcKhông logicBitwise KHÔNGDiễn viên phong cách CKích thước tính bằng byteChờ cuộc gọi không đồng bộĐịa chỉ củaHội nghịPhân bổ bộ nhớ độngPhân bổ mảng độngXóa bộ nhớ độngXóa mảng động+biểu thức-biểu thức++lvalue––lvalue!biểu thức~biểu thức(new_type)biểu thứcsizeof(type) or sizeof(biểu thức)co_await biểu thức&lvalue*biểu thứcnew typenew type[biểu thức]delete pointerdelete[] pointer
4 L->R->*.*Bộ chọn con trỏ thành viênBộ chọn đối tượng thành viênobject_pointer->*pointer_to_memberobject.*pointer_to_member
5 L->R*/%Phép nhânChiaChia lấy dưbiểu thức * biểu thứcbiểu thức / biểu thứcbiểu thức % biểu thức
6 L->R+-CộngTrừbiểu thức + biểu thứcbiểu thức – biểu thức
7 L->R<<>>Bitwise shift leftBitwise shift rightbiểu thức << biểu thứcbiểu thức >> biểu thức
8 L->R<=>So sánh ba chiềubiểu thức <=> biểu thức
9 L->R<<=>>=So sánh ít hơnSo sánh nhỏ hơn hoặc bằngSo sánh lớn hơnSo sánh lớn hơn hoặc bằngbiểu thức < biểu thứcbiểu thức <= biểu thứcbiểu thức > biểu thứcbiểu thức >= biểu thức
10 L->R==!=EqualityInequalitybiểu thức == biểu thứcbiểu thức != biểu thức
11 L->R&Bitwise ANDbiểu thức & biểu thức
12 L->R^Bitwise XORbiểu thức ^ biểu thức
13 L->R|Bitwise ORbiểu thức | biểu thức
14 L->R&&Logical ANDbiểu thức && biểu thức
15 L->R||Logical ORbiểu thức || biểu thức
16 R->Lthrowco_yield?:=*=/=%=+=-=<<=>>=&=|=^=Throw biểu thứcYield biểu thứcConditionalAssignmentMultiplication assignmentDivision assignmentModulus assignmentAddition assignmentSubtraction assignmentBitwise shift left assignmentBitwise shift right assignmentBitwise AND assignmentBitwise OR assignmentBitwise XOR assignmentthrow biểu thứcco_yield biểu thứcbiểu thức ? biểu thức : biểu thứclvalue = biểu thứclvalue *= biểu thứclvalue /= biểu thứclvalue %= biểu thứclvalue += biểu thứclvalue -= biểu thứclvalue <<= biểu thứclvalue >>= biểu thứclvalue &= biểu thứclvalue |= biểu thứclvalue ^= biểu thức
17 L->R,Comma operatorbiểu thức, biểu thức

Bạn hẳn đã nhận ra một số toán tử này, chẳng hạn như +, -, *, /, () và sizeof. Tuy nhiên, trừ khi bạn có kinh nghiệm với một ngôn ngữ lập trình khác, phần lớn các toán tử trong bảng này có thể sẽ khiến bạn không thể hiểu được ngay bây giờ. Đó là dự kiến ​​tại thời điểm này. Chúng ta sẽ đề cập đến nhiều người trong số họ trong phần này và phần còn lại sẽ được giới thiệu khi có nhu cầu.

Hỏi: Toán tử lũy thừa ở đâu?

C ++ không bao gồm một toán tử để tính lũy thừa (toán tử ^ có một hàm khác trong C ++). Chúng ta thảo luận thêm về lũy thừa trong bài – Mô đun và lũy thừa.

4. Dấu ngoặc đơn

Trong số học thông thường, bạn đã học được rằng bạn có thể sử dụng dấu ngoặc đơn để thay đổi thứ tự áp dụng các phép toán. Ví dụ: chúng ta biết rằng 4 + 2 * 3 đánh giá là 4 + (2 * 3), nhưng nếu bạn muốn nó đánh giá là (4 + 2) * 3 thay vào đó, bạn có thể đặt dấu ngoặc đơn rõ ràng để làm cho nó đánh giá theo cách bạn muốn. Điều này hoạt động trong C ++ vì dấu ngoặc đơn có một trong những mức ưu tiên cao nhất, vì vậy dấu ngoặc đơn thường đánh giá trước bất kỳ thứ gì bên trong chúng.

Bây giờ hãy xem xét một biểu thức như x && y || z Điều này có đánh giá là (x && y) || z hay x && (y || z)? Bạn có thể tra cứu bảng và thấy rằng && được ưu tiên hơn ||. Nhưng có quá nhiều toán tử và cấp độ ưu tiên nên khó có thể nhớ hết chúng. Để giảm sai lầm và làm cho code của bạn dễ hiểu hơn mà không cần tham chiếu đến bảng ưu tiên, bạn nên đặt dấu ngoặc đơn cho bất kỳ biểu thức phức hợp không tầm thường nào, để hiểu rõ mục đích của bạn là gì.

Cài ứng dụng cafedev để dễ dàng cập nhật tin và học lập trình mọi lúc mọi nơi tại đây.

Nguồn và Tài liệu tiếng anh tham khảo:

Tài liệu từ cafedev:

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!