Tất Tần Tật Về Lập Trình Hướng Đối Tượng (Phần 4)

Tất Tần Tật Về Lập Trình Hướng Đối Tượng (Phần 4)

phần trước chúng ta đã tìm hiểu về hàm khởi tạo và hàm hủy trong Trong phần này chúng ta sẽ cùng nhau tìm hiểu về con trỏ this và từ khóa struct trong C++ là gì và góp phần quan trọng như thế nào trong lập trình hướng đối tượng (OOP) nhé.

1. Con trỏ this:

This là một con trỏ đặc biệt dùng để trỏ đến địa chỉ của đối tượng hiện tại. Như vậy để truy cập đến các thuộc tính, phương thức của đối tượng hiện tại thì ta sẽ sử dụng con trỏ this. Mình lấy ví dụ như sau: 

#include <iostream>  
using namespace std;  
class Mayvitinh { 
    int chieudai;
    string mausac;
    int chieurong;
    public:  
       void setData(int chieudai, string mausac, int chieurong) {  
            this->mausac = mausac;    
            this->chieudai = chieudai;    
            this->chieurong = chieurong; 
       }    
       void showData() {
            cout << "Chieu dai may: " << this->chieudai << endl;
            cout << "Chieu rong may: " << this->chieurong << endl;
            cout << "Mau sac may: " << this->mausac << endl;
       }    
};

Trong ví dụ này mình đã tạo ra ba thuộc tính để lưu trữ thông tin của Mayvitinh là: chieudai, chieurong, mausac. Ngoài ra mình có tạo thêm phương thức setData() dùng để gán dữ liệu cho Mayvitinh, và showData() dùng để hiển thị dữ liệu.

Trong phương thức setData() mình đã sử dụng từ khóa this->ten_thuoc_tinh để thực hiện phép gán dữ liệu cho các thuộc tính, còn ở phương thức showData() mình cũng sử dụng cú pháp tương tự để hiển thị dữ liệu của các thuộc tính. Như vậy công dụng của từ khóa this chính là một con trỏ và trỏ đến địa chỉ của đối tượng hiện tại.

Câu hỏi đặt ra là đối tượng hiện tại tại là gì? Để hiểu rõ hơn thì hãy xem đoạn code sử dụng class trên như sau:

int main() { 
    // mayAsus
    Mayvitinh mayAsus;
    mayAsus.setData(25, "mau bac", 20);
    mayAsus.showData();    
     
    // mayAcer
    Mayvitinh mayAcer;
    mayAcer.setData(30, "mau do", 24);
    mayAcer.showData();
    return 0;  
}

Ví dụ trên sẽ cho ra kết quả:

Trong ví dụ này mình đã tạo ra hai đối tượng Mayvitinh đó là mayAcer và mayAsus, và con trỏ this của mayAcer sẽ trỏ đến chính đối tượng mayAcer, con trỏ this của mayAsus sẽ trỏ đến chính đối tượng mayAsus, đây ta gọi là đối tượng hiện tại.

Vậy các có nghĩ sẽ ra sao nếu chúng ta không sử dụng con trỏ this mà khai báo tên của tham số hàm trùng tên với dữ liệu thành viên của lớp ?

Hãy xem ví dụ dưới đây:

#include <iostream>  
using namespace std;  
class Mayvitinh { 
    int chieudai;
    string mausac;
    int chieurong;
    public:  
       Mayvitinh(int chieudai, string mausac, int chieurong) {  
            cout << "Trong ham khoi tao: " << endl;
            cout << "   Chieu dai: " << chieudai << endl;
            cout << "   Chieu rong: " << chieurong << endl;
            cout << "   Mau sac: " << mausac << endl;
            mausac = mausac;    
            chieudai = chieudai;    
            chieurong = chieurong; 
       }    
       void HienThi() {
            cout << "Thong tin may tinh: " << endl;
            cout << "Chieu dai may: " << chieudai << endl;
            cout << "Chieu rong may: " << chieurong << endl;
            cout << "Mau sac may: " << mausac << endl;
       }    
};
int main() { 
    // mayAsus
    Mayvitinh mayAsus = Mayvitinh(25, "mau do", 20);
    mayAsus.HienThi();
}

Code trên sẽ cho ra kết quả như sau: 

Thật bất ngờ khi kết quả không như những gì chúng ta mong đợi phải không nào ?

Mình xin được giải thích chương trình trên như sau:

  • Khi chúng ta khai báo tên của tham số hàm trùng tên với dữ liệu thành viên của lớp, thì bên trong hàm khởi tạo chương trình hiểu là biến tham số chứ không phải dữ liệu thành viên của lớp.
  • Như vậy ở ví dụ trên, bên trong thân hàm xây dựng ta gán chieudai = chieudai, chieurong = chieurong, mausac = mausac, thì chương trình hiểu chieudai, chieurong, mausac chính là biến truyền vào từ hàm xây dựng, chính vì vậy nó không cập nhật vào các thuộc tính của đối tượng.
  • Khi các dữ liệu thành viên như chieudai, chieurong, mausac không được khởi tạo giá trị nó sẽ có giá trị tự động cho chương trình tạo ra mà chúng ta không hề biết trước

Con trỏ this sẽ giúp chúng ta giải quyết được vấn về trên. Chúng ta sẽ dùng con trỏ this trong ví dụ trên như sau:

#include <iostream>  
using namespace std;  
class Mayvitinh { 
    int chieudai;
    string mausac;
    int chieurong;
    public:  
       Mayvitinh(int chieudai, string mausac, int chieurong) {  
            cout << "Trong ham khoi tao: " << endl;
            cout << "   Chieu dai: " << chieudai << endl;
            cout << "   Chieu rong: " << chieurong << endl;
            cout << "   Mau sac: " << mausac << endl;
            this->mausac = mausac;    
            this->chieudai = chieudai;    
            this->chieurong = chieurong; 
       }    
       void HienThi() {
            cout << "Thong tin may tinh: " << endl;
            cout << "Chieu dai may: " << this->chieudai << endl;
            cout << "Chieu rong may: " << this->chieurong << endl;
            cout << "Mau sac may: " << this->mausac << endl;
       }    
};
int main() { 
    // mayAsus
    Mayvitinh mayAsus = Mayvitinh(25, "mau do", 20);
    mayAsus.HienThi();
}

Kết quả chương trình sẽ là: 

Như vậy con trỏ this dùng để tham chiếu đến thể hiện hiện tại của lớp. Con trỏ this có thể sử dụng trong 3 cách như sau:

  • Nó có thể được sử dụng để truyền đối tượng hiện tại làm tham số cho phương thức khác.
  • Nó có thể được sử dụng để tham chiếu đến thể hiện hiện tại của lớp (như ở ví dụ trên).
  • Nó có thể được sử dụng để khai báo các chỉ mục.

Lưu ý: Chúng ta nên đặt tham số của hàm khởi tạo trùng tên với tên của dữ liệu thành viên và sử dụng con trỏ this trong hàm khởi tạo để quản lý chương trình chặt chẽ hơn thay vì đặt tên tham số theo các chữ cái như a, b, c... thì tên đó không có ý nghĩa gì hết.

2. Từ khóa static:

Trước khi đi vào tìm hiểu từ khóa static chúng ta cùng xem qua ví dụ sau đây:

#include <iostream>  
using namespace std;  
class Mayvitinh { 
    int chieudai;
    string tenmay;
    int chieurong;
    string noisanxuat;
    public:  
       Mayvitinh(int chieudai, string tenmay, int chieurong, string noisanxuat) {  
            this->tenmay = tenmay;    
            this->chieudai = chieudai;    
            this->chieurong = chieurong; 
            this->noisanxuat = noisanxuat;
       }    
       void HienThi() {
            cout << this->tenmay << endl;
            cout << "    Chieu dai may: " << this->chieudai << endl;
            cout << "    Chieu rong may: " << this->chieurong << endl;
            cout << "    Noi san xuat: " << this->noisanxuat << endl;
       }    
};
int main() { 
    Mayvitinh mayAsus = Mayvitinh(25, "may Asus", 20, "China");
    Mayvitinh mayAcer = Mayvitinh(30, "may Acer", 24, "China");
    Mayvitinh mayMac = Mayvitinh(35, "may Mac", 15, "China");
    mayAsus.HienThi();
    mayAcer.HienThi();
    mayMac.HienThi();
}

Chương trình sẽ cho kết quả:

Giả sử có 1000 máy vi tính đều sản xuất tại cùng một nước, thì phải cấp phát 1000 ô nhớ lưu trữ tên của nơi sản xuất, điều này gây ra lãng phí bộ nhớ.

Để khắc phục tình trạng đấy, chúng ta chỉ cần khai báo noisanxuat là biến static, thì khi chạy chương trình chỉ có một biến noisanxuat được khỏi tạo, và các đối tượng cùng chia sẻ chung một biến static này.

Cú pháp để sử dụng static:

static KieuDuLieu tenTruong;

Khởi tạo giá trị:

KieuDuLieu TenLop::tenTruongStatic = Gia tri;

Chúng ta sẽ áp dụng từ khóa static cho noisanxuat của chương trình bên trên như sau:

#include <iostream>  
using namespace std;  
class Mayvitinh { 
    int chieudai;
    string tenmay;
    int chieurong;
    public:  
       static string noisanxuat;
       Mayvitinh(int chieudai, string tenmay, int chieurong) {  
            this->tenmay = tenmay;    
            this->chieudai = chieudai;    
            this->chieurong = chieurong; 
       }    
       void HienThi() {
            cout << this->tenmay << endl;
            cout << "    Chieu dai may: " << this->chieudai << endl;
            cout << "    Chieu rong may: " << this->chieurong << endl;
            cout << "    Noi san xuat: " << this->noisanxuat << endl;
       }    
};

string Mayvitinh::noisanxuat = "China";

int main() { 
    Mayvitinh mayAsus = Mayvitinh(25, "may Asus", 20);
    Mayvitinh mayAcer = Mayvitinh(30, "may Acer", 24);
    Mayvitinh mayMac = Mayvitinh(35, "may Mac", 15);
    mayAsus.HienThi();
    mayAcer.HienThi();
    mayMac.HienThi();
}

Tạm kết

Vậy là chúng ta đã được tìm hiểu về con trỏ this và từ khóa static trong C++, bên cạnh đó cũng hiểu hơn về tầm quan trọng của chúng trong OOP. Mình hy vọng bài viết này sẽ giúp các bạn trong việc lập trình hướng đối tượng.

Nếu có góp ý hay thắc mắc các bạn có thể rate và comment bên dưới để những bài viết sau được tốt hơn nhé.

Cảm ơn các bạn đã dành thời gian theo dõi.