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ặc false).
    • 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: =, +=, -=, *=, /=, % =.

Ví dụ minh họa:

#include <iostream>
#include <string>

using namespace std;

int main() {
    int sn = 10;
    double st = 3.14;
    char kt = 'A';
    bool ld = true;
    string t = "C++";

    int s = sn + 5;
    bool lh = sn > st;
    bool dk = (sn > 0) && ld;

    cout << "So nguyen: " << sn << endl;
    cout << "Tong: " << s << endl;
    cout << "Lon hon: " << lh << endl;
    cout << "Dieu kien: " << dk << endl;
    cout << "Ten ngon ngu: " << t << endl;

    return 0;
}

Output:

So nguyen: 10
Tong: 15
Lon hon: 0
Dieu kien: 1
Ten ngon ngu: C++

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 ifelse 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>

using namespace std;

int main() {
    int d = 75;

    if (d >= 90) {
        cout << "Diem A" << endl;
    } else if (d >= 80) {
        cout << "Diem B" << endl;
    } else if (d >= 70) {
        cout << "Diem C" << endl;
    } else {
        cout << "Can co gang hon" << endl;
    }

    cout << "Cac so chan tu 0 den 10:" << endl;
    for (int i = 0; i <= 10; i += 2) {
        cout << i << " ";
    }
    cout << endl;

    int c = 5;
    cout << "Dem nguoc:" << endl;
    while (c > 0) {
        cout << c << "... ";
        c--;
    }
    cout << "Bat dau!" << endl;

    return 0;
}

Output:

Diem C
Cac so chan tu 0 den 10:
0 2 4 6 8 10 
Dem nguoc:
5... 4... 3... 2... 1... Bat dau!

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ới i = 0, lặp chừng nào i <= 10, mỗi lần lặp tăng i thêm 2, in ra các số chẵn.
  • Vòng lặp while bắt đầu với c = 5, lặp chừng nào c > 0, in ra giá trị hiện tại của c 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>

using namespace std;

int tong(int a, int b);

int main() {
    int s1 = 5;
    int s2 = 7;

    int kq = tong(s1, s2);

    cout << "Tong cua " << s1 << " va " << s2 << " la: " << kq << endl;
    cout << "Tong cua 10 va 20 la: " << tong(10, 20) << endl;

    return 0;
}

int tong(int a, int b) {
    return a + b;
}

Output:

Tong cua 5 va 7 la: 12
Tong cua 10 va 20 la: 30

Giải thích:

  • Chúng ta định nghĩa một hàm tên là tong nhận hai tham số kiểu intab, và trả về một giá trị kiểu int.
  • 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àm tong hai lần với các đối số khác nhau và lưu kết quả vào biến kq 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>

using namespace std;

int main() {
    int m[5] = {10, 20, 30, 40, 50};

    cout << "Phan tu thu 3 cua mang (chi so 2): " << m[2] << endl;

    cout << "Cac phan tu cua mang:" << endl;
    for (int i = 0; i < 5; ++i) {
        cout << m[i] << " ";
    }
    cout << endl;

    vector<int> v;

    v.push_back(100);
    v.push_back(200);
    v.push_back(300);

    cout << "Kich thuoc cua vector: " << v.size() << endl;

    cout << "Phan tu dau tien cua vector: " << v[0] << endl;

    cout << "Cac phan tu cua vector:" << endl;
    for (int x : v) {
        cout << x << " ";
    }
    cout << endl;

    return 0;
}

Output:

Phan tu thu 3 cua mang (chi so 2): 30
Cac phan tu cua mang:
10 20 30 40 50 
Kich thuoc cua vector: 3
Phan tu dau tien cua vector: 100
Cac phan tu cua vector:
100 200 300

Giải thích:

  • Mảng m đượ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> v được tạo ra lúc đầu rỗng. Phương thức push_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ùng range-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.
  • 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>

using namespace std;

int main() {
    int g = 100;

    int* ptr = &g;
    int& ref = g;

    cout << "Gia tri goc: " << g << endl;
    cout << "Gia tri qua con tro (*ptr): " << *ptr << endl;
    cout << "Gia tri qua tham chieu (ref): " << ref << endl;

    cout << "Dia chi cua g (&g): " << &g << endl;
    cout << "Dia chi ma con tro tro toi (ptr): " << ptr << endl;

    *ptr = 200;
    cout << "Gia tri sau khi thay doi qua con tro: " << g << endl;

    ref = 300;
    cout << "Gia tri sau khi thay doi qua tham chieu: " << g << endl;

    return 0;
}

Output:

Gia tri goc: 100
Gia tri qua con tro (*ptr): 100
Gia tri qua tham chieu (ref): 100
Dia chi cua g (&g): (dia chi)
Dia chi ma con tro tro toi (ptr): (dia chi)
Gia tri sau khi thay doi qua con tro: 200
Gia tri sau khi thay doi qua tham chieu: 300

Giải thích:

  • Chúng ta có biến g.
  • ptr là một con trỏ (int*) lưu địa chỉ của g (lấy bằng &g). *ptr truy cập giá trị tại địa chỉ đó.
  • ref là một tham chiếu (int&) đến g. Bất kỳ thao tác nào trên ref cũng chính là thao tác trên g.
  • 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 g, 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>

using namespace std;

class Vat {
public:
    string t;
    int ts;

    Vat(string a, int b) {
        t = a;
        ts = b;
        cout << "Mot con vat moi duoc tao ra: " << t << endl;
    }

    void keu() {
        cout << t << " dang keu!" << endl;
    }

    ~Vat() {
        cout << t << " bi huy." << endl;
    }
}; // Ket thuc dinh nghia Class phai co dau cham phay

int main() {
    Vat meo("Meo", 3);
    Vat cho("Cho", 5);

    cout << meo.t << " " << meo.ts << " tuoi." << endl;
    meo.keu();

    cout << cho.t << " " << cho.ts << " tuoi." << endl;
    cho.keu();

    return 0;
}

Output:

Mot con vat moi duoc tao ra: Meo
Mot con vat moi duoc tao ra: Cho
Meo 3 tuoi.
Meo dang keu!
Cho 5 tuoi.
Cho dang keu!
Cho bi huy.
Meo bi huy.

Giải thích:

  • Chúng ta định nghĩa class Vat với hai thuộc tính tts (đều là public).
  • Constructor Vat(string a, int b) 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ết Vat meo("Meo", 3);.
  • Method keu() chỉ đơn giản là in ra một thông báo.
  • Destructor ~Vat() đượ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àm main). 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ượng meocho từ lớp Vat và sử dụng toán tử . để truy cập các thuộc tính (t, ts) và gọi phương thức (keu()).

Comments

There are no comments at the moment.