Bài 40.1: Ôn tập kiến thức khóa học trong C++

Bài 40.1: Ôn tập kiến thức khóa học trong C++
Chào mừng trở lại series về C++! Sau một hành trình khá dài cùng nhau khám phá ngôn ngữ mạnh mẽ này, chúng ta đã đi qua rất nhiều khái niệm, từ những viên gạch cơ bản nhất cho đến những cấu trúc phức tạp hơn. Trước khi dấn thân vào các chủ đề nâng cao tiếp theo, đây là thời điểm vàng để chúng ta cùng nhau ngồi lại, xâu chuỗi và củng cố lại những kiến thức cốt lõi đã học.
Bài viết ôn tập này không chỉ là một danh sách các chủ đề, mà là một chuyến tàu lượn tốc hành qua những trạm quan trọng nhất trên bản đồ C++ của chúng ta. Hãy cùng nhau nhìn lại và đảm bảo rằng nền móng của bạn thật vững chắc nhé!
1. Biến, Kiểu Dữ Liệu và Toán Tử: Những Khối Xây Dựng Đầu Tiên
- Biến là trái tim của mọi chương trình, là nơi chúng ta lưu trữ dữ liệu. Mỗi biến cần có một kiểu dữ liệu xác định để C++ biết cách xử lý nó và phân bổ bộ nhớ phù hợp.
- Chúng ta đã làm quen với các kiểu dữ liệu nguyên thủy phổ biến như:
int
: Số nguyên.float
,double
: Số thực (số có phần thập phân).double
thường cung cấp độ chính xác cao hơn.char
: Ký tự đơn.bool
: Giá trị logic (true
hoặcfalse
).- Và cả
string
cho chuỗi ký tự (mặc dù không phải nguyên thủy, nhưng cực kỳ thông dụng).
- Các toán tử giúp chúng ta thực hiện các phép tính và thao tác trên dữ liệu:
- Toán tử số học:
+
,-
,*
,/
,%
(chia lấy dư). - Toán tử so sánh:
==
(bằng),!=
(khác),>
,<
,>=
,<=
. - Toán tử logic:
&&
(AND),||
(OR),!
(NOT). - Toán tử gán:
=
,+=
,-=
,*=
,/=
,% =
.
- Toán tử số học:
Ví dụ minh họa:
#include <iostream>
#include <string> // Cần include để dùng string
int main() {
// Khai báo và gán giá trị cho biến
int soNguyen = 10;
double soThuc = 3.14;
char kyTu = 'A';
bool laDung = true;
string ten = "C++";
// Sử dụng toán tử
int tong = soNguyen + 5; // Toán tử số học
bool lonHon = soNguyen > soThuc; // Toán tử so sánh
bool dieuKien = (soNguyen > 0) && laDung; // Toán tử logic
// In ra kết quả
cout << "So nguyen: " << soNguyen << endl;
cout << "Tong: " << tong << endl;
cout << "Lon hon: " << lonHon << endl; // In ra 1 (true) hoac 0 (false)
cout << "Dieu kien: " << dieuKien << endl;
cout << "Ten ngon ngu: " << ten << endl;
return 0;
}
Giải thích:
- Chúng ta khai báo các biến với kiểu dữ liệu khác nhau (
int
,double
,char
,bool
,string
). - Thực hiện các phép toán và so sánh đơn giản.
- Sử dụng
cout
để in giá trị của biến và kết quả các phép toán ra màn hình.endl
dùng để xuống dòng.
2. Cấu Trúc Điều Khiển: Chỉ Đường Cho Chương Trình
Chương trình của chúng ta không chỉ chạy tuần tự từ trên xuống dưới. Chúng ta cần các cấu trúc để đưa ra quyết định (chọn đường nào đi) và lặp lại các hành động (đi đường đó bao nhiêu lần).
- Câu lệnh điều kiện (
if
,else if
,else
): Giúp chương trình thực thi một khối code chỉ khi một điều kiện nhất định đúng.else if
vàelse
cung cấp các lựa chọn thay thế. - Câu lệnh lựa chọn (
switch
): Là một cách gọn gàng để xử lý nhiều trường hợp lựa chọn dựa trên giá trị của một biến. - Vòng lặp (
for
,while
,do-while
): Cho phép chúng ta lặp lại một khối code nhiều lần.for
: Thường dùng khi biết trước số lần lặp hoặc lặp qua các phần tử của một dãy.while
: Lặp chừng nào điều kiện còn đúng (kiểm tra điều kiện trước khi lặp).do-while
: Lặp ít nhất một lần, sau đó kiểm tra điều kiện để quyết định lặp tiếp hay không (kiểm tra điều kiện sau khi lặp).
Ví dụ minh họa:
#include <iostream>
int main() {
int diem = 75;
// if-else if-else
if (diem >= 90) {
cout << "Diem A" << endl;
} else if (diem >= 80) {
cout << "Diem B" << endl;
} else if (diem >= 70) {
cout << "Diem C" << endl;
} else {
cout << "Can co gang hon" << endl;
}
// Vòng lặp for
cout << "Cac so chan tu 0 den 10:" << endl;
for (int i = 0; i <= 10; i += 2) {
cout << i << " ";
}
cout << endl; // Xuong dong
// Vòng lặp while
int dem = 5;
cout << "Dem nguoc:" << endl;
while (dem > 0) {
cout << dem << "... ";
dem--;
}
cout << "Bat dau!" << endl;
return 0;
}
Giải thích:
- Phần
if-else if-else
kiểm tra điểm và in ra xếp loại tương ứng. - Vòng lặp
for
bắt đầu vớii = 0
, lặp chừng nàoi <= 10
, mỗi lần lặp tăngi
thêm 2, in ra các số chẵn. - Vòng lặp
while
bắt đầu vớidem = 5
, lặp chừng nàodem > 0
, in ra giá trị hiện tại củadem
và giảm nó đi 1 sau mỗi lần lặp.
3. Hàm (Functions): Phân Chia Công Việc
Khi chương trình trở nên lớn hơn, việc gom các đoạn code thực hiện một nhiệm vụ cụ thể vào thành hàm là cực kỳ quan trọng. Hàm giúp:
- Tái sử dụng code: Viết một lần, dùng nhiều nơi.
- Tổ chức code: Chia chương trình thành các khối nhỏ, dễ quản lý và đọc hiểu hơn.
- Trừu tượng hóa: Che giấu chi tiết triển khai phức tạp, chỉ cần biết hàm làm gì và dùng nó như thế nào.
Một hàm có thể nhận các tham số (input) và trả về một giá trị (output) thông qua câu lệnh return
.
Ví dụ minh họa:
#include <iostream>
// Khai báo (prototype) của hàm
int tinhTong(int a, int b);
int main() {
int so1 = 5;
int so2 = 7;
// Gọi hàm
int ketQua = tinhTong(so1, so2);
cout << "Tong cua " << so1 << " va " << so2 << " la: " << ketQua << endl;
// Gọi hàm với giá trị khác
cout << "Tong cua 10 va 20 la: " << tinhTong(10, 20) << endl;
return 0;
}
// Định nghĩa (implementation) của hàm
int tinhTong(int a, int b) {
return a + b; // Trả về tổng của a và b
}
Giải thích:
- Chúng ta định nghĩa một hàm tên là
tinhTong
nhận hai tham số kiểuint
làa
vàb
, và trả về một giá trị kiểuint
. - Hàm này thực hiện phép cộng đơn giản.
- Trong hàm
main
, chúng ta gọi hàmtinhTong
hai lần với các đối số khác nhau và lưu kết quả vào biếnketQua
hoặc in trực tiếp.
4. Mảng (Arrays) & vector: Lưu Trữ Bộ Sưu Tập Dữ Liệu
Khi cần lưu trữ một tập hợp các giá trị có cùng kiểu, chúng ta sử dụng các cấu trúc dữ liệu tập hợp.
- Mảng (Arrays): Là một dãy các phần tử cùng kiểu được lưu trữ liền kề trong bộ nhớ. Kích thước của mảng phải được xác định tại thời điểm biên dịch và không thể thay đổi sau đó.
vector
: Là một phần tử của Thư viện Chuẩn C++ (STL). Nó giống như một mảng, nhưng có kích thước động, có thể thay đổi trong quá trình chạy chương trình.vector
cung cấp nhiều tiện ích hơn mảng thô.
Ví dụ minh họa:
#include <iostream>
#include <vector> // Cần include để dùng vector
int main() {
// Mảng cố định (kich thuoc 5 phan tu)
int mangSoNguyen[5] = {10, 20, 30, 40, 50};
// Truy cap phan tu mang (bat dau tu chi so 0)
cout << "Phan tu thu 3 cua mang (chi so 2): " << mangSoNguyen[2] << endl; // In ra 30
// Duyet mang
cout << "Cac phan tu cua mang:" << endl;
for (int i = 0; i < 5; ++i) {
cout << mangSoNguyen[i] << " ";
}
cout << endl;
// vector (bat dau rong)
vector<int> vecSoNguyen;
// Them phan tu vao vector
vecSoNguyen.push_back(100);
vecSoNguyen.push_back(200);
vecSoNguyen.push_back(300);
// Kich thuoc hien tai cua vector
cout << "Kich thuoc cua vector: " << vecSoNguyen.size() << endl;
// Truy cap phan tu vector (cung bat dau tu chi so 0)
cout << "Phan tu dau tien cua vector: " << vecSoNguyen[0] << endl; // In ra 100
// Duyet vector (dung range-based for loop - C++11 tro len)
cout << "Cac phan tu cua vector:" << endl;
for (int so : vecSoNguyen) {
cout << so << " ";
}
cout << endl;
return 0;
}
Giải thích:
- Mảng
mangSoNguyen
được khai báo với kích thước cố định là 5 và khởi tạo giá trị. Chúng ta truy cập các phần tử bằng chỉ số[]
. vector<int> vecSoNguyen
được tạo ra lúc đầu rỗng. Phương thứcpush_back()
được dùng để thêm các phần tử vào cuối vector, làm cho kích thước của nó tăng lên động.- Kích thước của vector được lấy bằng phương thức
size()
. - Ví dụ cho thấy cách duyệt cả mảng truyền thống (dùng vòng lặp
for
với chỉ số) và vector (dùngrange-based for loop
tiện lợi).
5. Con Trỏ (Pointers) & Tham Chiếu (References): Làm Việc Trực Tiếp Với Bộ Nhớ
Đây là hai khái niệm đặc trưng và mạnh mẽ của C++, cho phép chúng ta làm việc ở cấp độ bộ nhớ.
- Con trỏ (Pointer): Là một biến đặc biệt lưu trữ địa chỉ bộ nhớ của biến khác.
- Sử dụng toán tử
&
(address-of) để lấy địa chỉ của một biến. - Sử dụng toán tử
*
(dereference) để truy cập giá trị tại địa chỉ mà con trỏ đang trỏ tới.
- Sử dụng toán tử
- Tham chiếu (Reference): Là một bí danh (alias) cho một biến đã tồn tại. Một khi đã khởi tạo, tham chiếu không thể thay đổi để tham chiếu đến biến khác. Nó về cơ bản là một tên khác cho cùng một vị trí bộ nhớ.
Ví dụ minh họa:
#include <iostream>
int main() {
int giaTri = 100;
// Khai bao con tro va tro toi dia chi cua giaTri
int* conTroGiaTri = &giaTri;
// Khai bao tham chieu va tham chieu den giaTri
int& thamChieuGiaTri = giaTri;
// In ra gia tri goc, gia tri qua con tro, gia tri qua tham chieu
cout << "Gia tri goc: " << giaTri << endl; // 100
cout << "Gia tri qua con tro (*conTroGiaTri): " << *conTroGiaTri << endl; // 100
cout << "Gia tri qua tham chieu (thamChieuGiaTri): " << thamChieuGiaTri << endl; // 100
// In ra dia chi cua gia tri goc va dia chi ma con tro dang tro toi
cout << "Dia chi cua giaTri (&giaTri): " << &giaTri << endl;
cout << "Dia chi ma con tro tro toi (conTroGiaTri): " << conTroGiaTri << endl; // Giong dia chi cua giaTri
// Thay doi gia tri qua con tro
*conTroGiaTri = 200;
cout << "Gia tri sau khi thay doi qua con tro: " << giaTri << endl; // 200
// Thay doi gia tri qua tham chieu
thamChieuGiaTri = 300;
cout << "Gia tri sau khi thay doi qua tham chieu: " << giaTri << endl; // 300
return 0;
}
Giải thích:
- Chúng ta có biến
giaTri
. conTroGiaTri
là một con trỏ (int*
) lưu địa chỉ củagiaTri
(lấy bằng&giaTri
).*conTroGiaTri
truy cập giá trị tại địa chỉ đó.thamChieuGiaTri
là một tham chiếu (int&
) đếngiaTri
. Bất kỳ thao tác nào trênthamChieuGiaTri
cũng chính là thao tác trêngiaTri
.- Thay đổi giá trị thông qua con trỏ hoặc tham chiếu đều làm thay đổi giá trị của biến gốc
giaTri
, chứng tỏ chúng cùng "nhìn" vào một vị trí bộ nhớ.
6. Lập Trình Hướng Đối Tượng (OOP): Class & Object Cơ Bản
OOP là một mô hình lập trình mạnh mẽ giúp quản lý độ phức tạp của các dự án lớn bằng cách tổ chức code xoay quanh các đối tượng (objects).
- Class (Lớp): Là một bản thiết kế hoặc khuôn mẫu để tạo ra các đối tượng. Nó định nghĩa các thuộc tính (dữ liệu - gọi là members) và hành vi (hàm - gọi là methods) mà các đối tượng thuộc lớp đó sẽ có.
- Object (Đối tượng): Là một thể hiện cụ thể (instance) của một lớp. Mỗi đối tượng có dữ liệu riêng của nó theo định nghĩa của lớp.
- Access Specifiers (
public
,private
,protected
): Kiểm soát khả năng truy cập vào các members và methods của lớp từ bên ngoài.public
có thể truy cập từ mọi nơi;private
chỉ có thể truy cập từ bên trong lớp đó. - Constructor (Hàm tạo): Là một phương thức đặc biệt trong lớp, có cùng tên với lớp, được gọi tự động khi một đối tượng của lớp đó được tạo ra. Nó thường dùng để khởi tạo dữ liệu cho đối tượng mới.
Ví dụ minh họa:
#include <iostream>
#include <string>
// Dinh nghia mot Class don gian
class ConVat {
public: // Cac thanh phan co the truy cap tu ben ngoai
string ten;
int tuoi;
// Constructor (Ham tao)
ConVat(string tenConVat, int tuoiConVat) {
ten = tenConVat;
tuoi = tuoiConVat;
cout << "Mot con vat moi duoc tao ra: " << ten << endl;
}
// Method (Ham thanh vien)
void keu() {
cout << ten << " dang keu!" << endl;
}
// Destructor (Ham huy - don dep khi doi tuong bi huy)
~ConVat() {
cout << ten << " bi huy." << endl;
}
}; // Ket thuc dinh nghia Class phai co dau cham phay
int main() {
// Tao cac Object (the hien) tu Class ConVat
ConVat meo("Meo", 3); // Goi constructor
ConVat cho("Cho", 5); // Goi constructor
// Truy cap thuoc tinh va goi phuong thuc cua Object
cout << meo.ten << " " << meo.tuoi << " tuoi." << endl;
meo.keu();
cout << cho.ten << " " << cho.tuoi << " tuoi." << endl;
cho.keu();
// Khi main ket thuc, cac object meo va cho se bi huy, goi destructor
return 0;
}
Giải thích:
- Chúng ta định nghĩa
class ConVat
với hai thuộc tínhten
vàtuoi
(đều làpublic
). - Constructor
ConVat(string tenConVat, int tuoiConVat)
nhận tên và tuổi khi tạo đối tượng và gán vào thuộc tính của đối tượng đó. Nó được gọi ngay khi chúng ta viếtConVat meo("Meo", 3);
. - Method
keu()
chỉ đơn giản là in ra một thông báo. - Destructor
~ConVat()
được gọi khi đối tượng bị hủy (ví dụ, khi nó ra khỏi phạm vi tồn tại, như cuối hàmmain
). Nó giúp thực hiện các tác vụ "dọn dẹp" nếu cần. - Trong
main
, chúng ta tạo hai đối tượngmeo
vàcho
từ lớpConVat
và sử dụng toán tử.
để truy cập các thuộc tính (ten
,tuoi
) và gọi phương thức (keu()
).
Comments