[C++ OOP Thực Chiến] Bài 8: Định nghĩa phương thức của Class - Khai phá sức mạnh của inline, const và static
Chào anh em! Trong các bài trước, chúng ta đã biết Class gồm có Thuộc tính (Data) và Phương thức (Hàm). Việc khai báo tên hàm thì rất dễ, nhưng việc "viết ruột" (Định nghĩa - Define) cho các hàm đó lại có nhiều cấp độ.
Một Junior chỉ viết hàm cho code chạy. Nhưng một Kỹ sư C++ sẽ biết dùng các từ khóa như const hay static để biến các phương thức đó thành một hệ thống chặt chẽ, tối ưu hiệu năng và ngăn chặn đồng nghiệp... code ngu làm sập hệ thống.
Hôm nay chúng ta sẽ tìm hiểu 2 cách định nghĩa phương thức và 2 từ khóa quyền lực nhất đi kèm với nó.
1. Hai vị trí để định nghĩa Phương thức
Khi viết nội dung cho một phương thức, bạn có 2 lựa chọn:
Cách 1: Định nghĩa ngay bên trong Class (Inline Method)
Đây là cách nhanh nhất và hay được dùng cho các hàm cực kỳ ngắn (như Getter/Setter).
- Ưu điểm: C++ sẽ ngầm hiểu đây là hàm
inline. Khi code được biên dịch, thay vì "nhảy" đến vùng nhớ chứa hàm (gây tốn thời gian), C++ sẽ "copy-paste" thẳng ruột hàm vào nơi gọi nó. Hiệu năng cực cao! - Nhược điểm: Nếu hàm quá dài (chứa vòng lặp, logic phức tạp) mà để bên trong Class thì file của bạn sẽ rất khó đọc.
Cách 2: Định nghĩa bên ngoài Class (Sử dụng toán tử ::)
Với các hàm logic nghiệp vụ phức tạp, chúng ta chỉ Khai báo tên hàm trong Class, và mang phần "ruột" ra bên ngoài để định nghĩa, sử dụng toán tử phân giải phạm vi TênClass::TênHàm.
2. Vũ khí phòng thủ: Phương thức const
Trong thực tế, bạn sẽ thường xuyên truyền Object vào một hàm khác dưới dạng Tham chiếu (&) để tiết kiệm bộ nhớ (không bị copy). Nhưng lỡ cái hàm đó vô tình sửa mất dữ liệu của Object thì sao?
Đó là lúc phương thức const xuất hiện. Khi bạn đặt chữ const ở cuối một phương thức, bạn đang lập một "Lời thề danh dự" với C++: "Hàm này chỉ ĐỌC dữ liệu, tuyệt đối không thay đổi bất kỳ thuộc tính nào của Class!".
3. Vũ khí dùng chung: Phương thức static
Bình thường, để gọi một phương thức, bạn PHẢI tạo ra một Object (ví dụ: myTicket.book()).
Nhưng nếu bạn muốn viết một hàm tiện ích chung (như hàm đếm xem có tổng cộng bao nhiêu vé đã được bán ra trên toàn hệ thống), bạn không thể nhét nó vào một vé cụ thể nào được.
Từ khóa static biến một phương thức thành Tài sản chung của toàn bộ Class. Bạn có thể gọi nó trực tiếp bằng tên Class mà không cần tạo Object (ví dụ: Ticket::getTotalSold()).
4. Code Demo: Hệ thống quản lý User Session
Hãy xem cách các khái niệm trên kết hợp lại trong một bài toán Backend thực tế:
#include <iostream>
#include <string>
using namespace std;
class UserSession {
private:
string username;
bool isLoggedIn;
// Thuộc tính static: Dùng chung cho TẤT CẢ các Object UserSession
static int activeUsers;
public:
// CÁCH 1: Định nghĩa ngay bên trong Class (Tốt cho hàm ngắn)
UserSession(string user) {
username = user;
isLoggedIn = false;
}
// Phương thức CONST: Lời thề KHÔNG làm thay đổi dữ liệu Class
string getUsername() const {
// isLoggedIn = true; // LỖI COMPILER NGAY: Vì đây là hàm const!
return username;
}
// Phương thức STATIC: Có thể gọi mà không cần tạo Object
static int getActiveUsers() {
return activeUsers; // Chỉ được phép thao tác với biến static
}
// CÁCH 2: Chỉ Khai báo ở đây, đem ra ngoài định nghĩa
void login();
void logout();
};
// --- Khởi tạo biến static ở ngoài Class (Bắt buộc trong C++) ---
int UserSession::activeUsers = 0;
// --- ĐỊNH NGHĨA PHƯƠNG THỨC BÊN NGOÀI BẰNG TOÁN TỬ :: ---
void UserSession::login() {
if (!isLoggedIn) {
isLoggedIn = true;
activeUsers++; // Tăng biến dùng chung
cout << "[INFO] " << username << " da dang nhap.\n";
}
}
void UserSession::logout() {
if (isLoggedIn) {
isLoggedIn = false;
activeUsers--; // Giảm biến dùng chung
cout << "[INFO] " << username << " da dang xuat.\n";
}
}
// --------------------------------------------------------
int main() {
// Gọi hàm static TRƯỚC KHI tạo bất kỳ Object nào
cout << "So user online ban dau: " << UserSession::getActiveUsers() << "\n\n";
UserSession user1("john_doe");
UserSession user2("alice_99");
user1.login();
user2.login();
// Gọi lại hàm static để thấy sự thay đổi toàn cục
cout << "\nSo user online hien tai: " << UserSession::getActiveUsers() << "\n\n";
user1.logout();
return 0;
}
Nhận xét code:
- Hàm getUsername() cực kỳ an toàn vì có const, không ai có thể dùng nó để hack trạng thái login.
- Hàm getActiveUsers() có thể gọi bất cứ lúc nào thông qua UserSession::, đóng vai trò như một bảng thống kê toàn hệ thống.
- Các hàm login và logout phức tạp được định nghĩa tách biệt bên ngoài, giúp phần khai báo Class ở trên trông rất gọn gàng.
Tạm kết & Gợi mở
Đến đây, các bạn đã nắm trong tay cách viết ruột (implement) cho các phương thức một cách chuyên nghiệp nhất, biết bảo vệ dữ liệu với const và quản lý trạng thái chung với static.
Nhưng nhìn lại code ở phần 4, các bạn sẽ thấy: Dù chúng ta đã đẩy các hàm login(), logout() ra bên ngoài Class bằng toán tử ::, thì tất cả chúng vẫn đang... chen chúc trong cùng một file main.cpp! Nếu dự án có 50 Class, cái file này sẽ phình to đến hàng ngàn dòng code, không ai có thể đọc và bảo trì nổi.
Đã đến lúc chúng ta phải "phẫu thuật" tách chúng ra thành những mảnh ghép độc lập. Hẹn gặp lại anh em ở Bài 9: Định nghĩa phương thức bằng cách chia file - Nghệ thuật quản lý Source Code chuẩn Enterprise! Nhớ Upvote để mình sớm ra bài tiếp theo nhé!
All rights reserved