Trong lập trình hướng đối tượng C++, class và object là hai khái niệm nền tảng. Class có thể được xem như một cấu trúc dữ liệu nâng cao cho phép định nghĩa kiểu do người dùng tạo, trong khi object là một thể hiện cụ thể của class đó.
1. Định nghĩa Class và Object
Class trong C++ tương tự như struct trong C nhưng có nhiều tính năng mạnh mẽ hơn. Một class bao gồm dữ liệu (thành viên) và các hàm (phương thức) thao tác trên dữ liệu đó. Object là biến được tạo từ class.
class Person {
private:
string _name;
int _age;
public:
void introduce() {
std::cout << "Name: " << _name << ", Age: " << _age;
}
};
Ở đây, class là từ khóa khai báo class, Person là tên class, và các biến bên trong được gọi là thành viên. Dấu chấm phẩy sau dấu ngoặc nhọn là bắt buộc.
2. Các Access Specifiers (Bộ chỉ định truy cập)
- public: Các thành viên có thể truy cập từ bên ngoài class.
- private: Chỉ truy cập được từ bên trong class.
- protected: Tương tự private, nhưng có thể truy cập từ class kế thừa.
Tính đóng gói (encapsulation) được thể hiện qua việc sử dụng private để ẩn dữ liệu, chỉ cho phép truy cập thông qua các phương thức public.
3. Sự khác biệt giữa struct và class
Trong C++, struct mặc định là public, còn class mặc định là private. C++ kế thừa struct từ C, nhưng struct trong C++ có thể chứa cả dữ liệu lẫn hàm, ngược lại với struct trong C chỉ chứa dữ liệu.
4. Phạm vi (Scope) của Class
Tất cả thành viên của class nằm trong phạm vi của class đó. Khi định nghĩa phương thức bên ngoài class, cần sử dụng toán tử :: để chỉ rõ class sở hữu.
class Teacher {
public:
void showInfo();
private:
string _major;
};
void Teacher::showInfo() {
std::cout << "Major: " << _major;
}
5. Khởi tạo Object (Instantiation)
Khởi tạo object là quá trình tạo ra một biến từ class. Ví dụ: Teacher t1; tạo một object t1 thuộc class Teacher.
6. Kích thước của Class
Kích thước của class được tính dựa trên các thành viên dữ liệu, tuân theo quy tắc alignment (căn chỉnh bộ nhớ). Ví dụ, một class có hai mảng char (10 và 5 byte) và một int (4 byte) sẽ có kích thước là 20 byte do alignment yêu cầu kích thước là bội số của kích thước thành viên lớn nhất (4 byte).
Các hàm thành viên mặc định trong C++
C++ cung cấp 6 hàm thành viên mặc định cho mỗi class: Constructor, Destructor, Copy Constructor, Copy Assignment Operator, Move Constructor, và Move Assignment Operator.
1. Constructor (Hàm tạo)
Constructor được gọi tự động khi object được tạo, dùng để khởi tạo dữ liệu. Nó có tên trùng với tên class và không có kiểu trả về.
class Point {
private:
int _x, _y;
public:
Point() { _x = 0; _y = 0; } // Default constructor
};
Nếu không khai báo, compiler sẽ tạo default constructor. Constructor cũng có thể được overload với tham số.
2. Destructor (Hàm hủy)
Destructor được gọi khi object kết thúc vòng đời, dùng để giải phóng tài nguyên. Tên destructor là tên class với dấu ~ ở đầu.
class Buffer {
private:
int* _data;
public:
Buffer(int size) { _data = new int[size]; }
~Buffer() { delete[] _data; }
};
3. Copy Constructor (Hàm tạo sao chép)
Copy constructor tạo object mới từ một object đã tồn tại. Tham số phải là tham chiếu (&) để tránh đệ quy vô hạn. Nếu không định nghĩa, compiler sẽ tạo shallow copy (sao chép nông).
class Vector {
public:
Vector(const Vector& other) {
_size = other._size;
_data = new int[_size];
for (int i = 0; i < _size; i++)
_data[i] = other._data[i];
}
private:
int* _data;
int _size;
};
Shallow copy có thể gây lỗi khi có con trỏ động (double deletion). Vì vậy, cần tự định nghĩa deep copy khi class quản lý bộ nhớ động.
4. Copy Assignment Operator (Toán tử gán sao chép)
Toán tử gán sao chép (operator=) được gọi khi gán object này cho object khác. Nó nên trả về tham chiếu và kiểm tra tự gán.
class String {
public:
String& operator=(const String& other) {
if (this != &other) {
delete[] _str;
_str = new char[strlen(other._str) + 1];
strcpy(_str, other._str);
}
return *this;
}
private:
char* _str;
};
Nếu không khai báo, compiler sẽ tạo bản mặc định thực hiện sao chép từng byte.
Kết
Nắm vững class, object, và các hàm thành viên mặc định là bước đầu tiên để làm chủ lập trình hướng đối tượng trong C++. Đặc biệt, khi làm việc với bộ nhớ động, hãy luôn định nghĩa copy constructor và copy assignment operator để tránh lỗi.