Hàm ảo và lớp ảo trong C++

Hàm ảo giống như một hàm quá tải, nhưng điều đặc biệt ở đây là: kiểu dữ liệu, số lượng và kiểu dữ liệu của các tham số của hàm ảo ở cả hai lớp cơ sở và dẫn xuất đều như nhau ! Hàm ảo là thành phần của một lớp, được khai báo trong lớp cơ sở rồi nhưng lại được khai báo lại trong lớp dẫn xuất với từ khoá “virtual” ở đằng trước. Không phải tự dưng người ta làm điều này vô ích, hàm ảo tạo nên tính đa hình trong c++ là bởi vì có thể nói một “giao diện” cho nhiều phương thức. Có nghĩa là với một thông điệp đó thôi mà  cho nhiều kết quả khác nhau khi con trỏ của lớp cơ sở trỏ đến đối tượng của một lớp nào đó (không nói đến con trỏ của lớp dẫn xuất vì nó không thể trỏ đến đối tượng của lớp cơ sở được !). Chúng ta gọi hàm ảo này bằng con trỏ vừa được nhắc đến ở trên. Một ví dụ cho hàm ảo:

#include<iostream>

using namespace std;

class Base

{

—-int x;

public:

—-virtual void setvalue(int i){x=i;cout<<“\n Lop co so;”;}

—-virtual int getvalue(){return x;}

};

class Derived:public Base

{

—-int y;

public:

—-void setvalue(int i){y=i;cout<<“\n Lop dan xuat”;}

—-int getvalue(){return y;}

};

void main()

{

—-Base*p, o1;

—-Derived obj, *p1;

—-p=&obj; // con trỏ lớp cơ sở trỏ đến đối tượng của lớp dẫn xuất

—-p->setvalue(5); //nhận giá trị của lớp dẫn xuất

—p=&o1; //trỏ đến con trỏ trong cùng lớp cơ sở

—-p->setvalue(5); //nhận giá trị của lớp cơ sở

—-cin.get();

}

Chạy thử chương trình sẽ biết ngay điều lý thú này.

Còn một điều đáng chú ý nữa, hàm ảo này có thể không được định nghĩa trong lớp cơ sở mà chỉ được khai báo thôi! VD: virtual void setvalue(int i)=0. Thế lúc này chúng ta gọi nó là “hàm ảo thuần tuý”. Lớp cơ sở mà chứa nó thì vô tình được là lớp cơ sở ảo, và lớp ảo này không thể có đối tượng của riêng mình, tuy nhiên chúng vẫn có thể có con trỏ (vd: base*P), con trỏ này sẽ trỏ đến các đối tượng của các lớp dẫn xuất, từ đó cũng tạo nên tính đa hình. Điều nữa là lớp nào mà kế thừa lớp này thì nhất định phải định nghĩa các hàm ảo thuần tuý này, nếu không trình biên dịch sẽ báo lỗi. Trường hợp có 3 lớp Base, Derived, Derived1 mà Base là lớp cơ sở ảo, Derived thừa kế Base, Derived1 lại thừa kế Derived, lúc này lớp Derived phải định nghĩa hàm ảo thuần tuý thì không nói làm gì nhưng lớp Derived1 nếu muốn con trỏ của lớp Base trỏ đến đối tượng của mình mà cho kế quá đúng thì hiển nhiên cũng phải định nghĩa lại hàm ảo thuần tuý này (mặc dù trình biên dich không báo lỗi khi không định nghĩa lại).Viết khai báo hàm ảo thuần tuý như sau:virtual kiểu_hàm tên_hàm(danh sách đối số) = 0; VD:

#include<iostream>
using namespace std;
class Base
{
—-int x;
public:
—-virtual void setvalue(int i)=0;
—-virtual int getvalue()=0;
};
class Derived1:public Base{
—-int y;
public:
—-void setvalue(int i){y=i;cout<<“\n Lop dan xuat 1”;}
—-int getvalue(){return y;}
};
class Derived2:public Derived1{
—-int z;

public:
—-void setvalue(int i){z=i;cout<<“\n Lop dan xuat 2”;}
—-int getvalue(){return z;}
};

void main(){
—-Base*p;
//    Base o1; //sai vì lớp cơ sở ảo không có đối tượng riêng của nó
—-Derived1 obj;
—-Derived2 o2;
—-p=&obj; //trỏ đến đối tượng của lớp dẫn xuất thứ 1
—-p->setvalue(5);
—-p=&o2; //trỏ đến đối tượng của lớp dẫn xuất thứ 2
—-p->setvalue(6);//kết quả sẽ là: “lớp dẫn xuất 2” nếu ta không định nghĩa lại ở Derived1
—-cin.get();
}

Advertisement

Share this:

Thích bài này:

Thích

Đang tải…