Lập trình hướng đối tượng - 15


nếu khai báo trong phạm vi lớp:

virtual <Kiểu trả về> <Tên phương thức>([<tham số>]);

nếu định nghĩa ngoài phạm vi lớp:

virtual <Kiểu trả về> <Tên lớp>::<Tên phương thức>([<tham số>])

{} Ví dụ 3.13:

class Car

{

public:

virtual void show();

Có thể bạn quan tâm!

Xem toàn bộ 256 trang tài liệu này.

};

là khai báo phương thức ảo show() cđa lớp Car: phương thức không có tham số và không cần giá trị trả về (void).

Lập trình hướng đối tượng - 15

Lưu ý:

từ khoá virtual có thể đặt trước hay sau kiểu trả về cđa phương thức.

Với cùng một phương thức được khai báo ở lớp cơ sở lẫn lớp dẫn xuất, chỉ cần dùng từ khoá virtual ở một trong hai lần định nghĩa phương thức đó là đđ: hoặc ở lớp cơ sở, hoặc ở lớp dẫn xuất.

Trong trường hợp cây thừa kế có nhiều mức, cũng chỉ cần khai báo phương thức là ảo (virtual) ở một mức bất kì. Khi đó, tất cả các phương thức trùng tên với phương

thức đó ở tất cả các mức đều được coi là phương thức ảo.

Đôi khi không cần thiết phải định nghĩa chồng (trong lớp dẫn xuất) một phương thức đã được khai báo là phương thức ảo trong lớp cơ sở.


3.10.2. Quy tắc gọi phương thức ảo

Một khi phương thức được khai báo là ảo thì khi một con trỏ gọi đến phương thức đó, chương trình sẽ thực hiện phương thức tương ứng với đối tượng mà con trỏ đang trỏ tới, thay vì thực hiện phương thức cđa lớp cùng kiểu với con trỏ. Đây

được gọi là hiện tượng đa hình (tương ứng bội) trong C++.

Chương trình sau minh hoạ việc sử dụng phương thức trừu tượng: lớp Bus thừa kế từ lớp Car, hai lớp này cùng định nghĩa phương thức trừu tượng show(). Khi ta dùng một con trỏ có kiểu lớp Car trỏ vào địa chỉ cđa một đối tượng kiểu Car, nó


sẽ gọi phương thức show() cđa lớp Car. Khi ta dùng cũng con trỏ đó, trỏ vào địa chỉ cđa một đối tượng kiểu Bus, nó sẽ gọi phương thức show() cđa lớp Bus.

Ví dụ 3.14:

#include<stdio.h>

#include<conio.h>

#include<string.h>

/* Định nghĩa lớp Car */ class Car

{

private:

int speed; // Tốc độ

char mark[20]; // Nhãn hiệu float price; // Giá xe

public:

int getSpeed(){return speed;};// Đọc tốc độ xe char[] getMark(){return mark;};// Đọc nhãn xe float getPrice(){return price;};// Đọc giá xe

// Khởi tạo thông tin về xe

Car(int speedIn=0, char markIn[]=”” , float priceIn=0); virtual void show(); // Giới thiệu xe, phương thức ảo

};

/* Khai báo phương thức bên ngoài lớp */ Car::Car(int speedIn, char markIn[], float priceIn)

{

speed = speedIn; strcpy(mark, markIn); price = priceIn;

}

// Phương thức ảo giới thiệu xe virtual void Car::show()

{

cout << This is a << mark << having a speed of

<< speed << km/h and its price is $<< price << endl;


return;

}

/* Định nghĩa lớp Bus thừa kế từ lớp Car */ class Bus: public Car

{

int label; // Số hiệu tuyền xe public:

Bus(int sIn=0, char mIn[]=”” , float pIn=0, int lIn=0); void show(); // Giới thiệu xe

};

Bus::Bus(int sIn, char mIn[], float pIn, int lIn):Car(sIn, mIn, pIn)

{

label = lIn;

}

// Định nghĩa chồng phương thức ảo void Bus::show(){ // Giới thiệu xe bus

cout << This is a bus of type << getMark() << , on the line

<< label << , having a speed of << getSpeed()

<< km/h and its price is $<< getPrice() << endl; return;

}

// Chương trình chính void main()

{

clrscr();

Car *ptrCar, myCar(100, Ford, 3000);

Bus myBus(150, Mercedes, 5000, 27);// biến đối tượng cđa lớp Bus ptrCar = &myCar; // Trỏ đến đối tượng lớp Car

ptrCar->show(); // Phương thức cđa lớp Car ptrCar = &myBus; // Trỏ đến đối tượng lớp Bus ptrCar->show(); // Phương thức cđa lớp Bus return;

}


Khi thực hiện chương trình ta thu được kết quả như sau:

This is a Ford having a speed of 100km/h and its price is $3000 This is a bus of type Mercedes, on the line 27, having a speed of 150km/h and its price is $5000

Dòng thứ nhất là kết quả khi con trỏ ptrCar trỏ đến địa chỉ cđa đối tượng myCar, thuộc lớp Car nên sẽ gọi phương thức show() cđa lớp Car với các dữ liệu cđa đối tượng myCar: (100, Ford, 3000). Dòng thứ hai tương ứng là kết quả khi con trỏ ptrCar trỏ đến địa chỉ cđa đối tượng myBus,thuộc lớp Bus nên sẽ gọi phương thức show() cđa lớp Bus, cùng với các tham số cđa đối tượng myBus: (150, Mercedes, 5000, 27).

Lưu ý:

Trong trường hợp ở lớp dẫn xuất không định nghĩa lại phương thức ảo, thì chương trình sẽ gọi phương thức cđa lớp cơ sở, nhưng với dữ liệu cđa lớp dẫn xuất. trong chương trình trên, lớp Bus không định nghĩa chồng phương thức ảo show() thì kết quả hiển thị sẽ là hai dòng thông báo giống nhau, chỉ khác nhau ở dữ liệu cđa hai đối tượng khác nhau:

This is a Ford having a speed of 100km/h and its price is $3000

This is a Mercedes having a speed of 150km/h and its price is $5000


3.10.3. Tương ứng bội

Một khi phương thức được khai báo là phương thức ảo thì khi một con trỏ gọi

đến phương thức đó, chương trình sẽ thực hiện phương thức tương ứng với đối tượng mà con trỏ đang trỏ tới, thay vì thực hiện phương thức cđa lớp cùng kiểu với con trỏ. Đây được gọi là hiện tượng đa hình (tương ứng bội) trong C++.

Có thể sử dụng tương ứng bội để tổ chức thực hiện các thuật toán khác nhau trên cùng một bài toán như sau :

Lớp cơ sở trừu tượng sẽ chứa chứa dữ liệu bài toán và một phương thức ảo

Mỗi lớp dẫn xuất ứng với một thuật toán cụ thể.

Sử dụng một mảng con trỏ cđa lớp cơ sở và gán cho mỗi phần tử mảng địa chỉ cđa một đối tượng cđa lớp dẫn xuất. Sau đó, dùng các phần tử mảng để gọi tới các phương thức ảo

Xét bài toán tìm kiếm: Cho một dãy gồm n khoá K1, K2, .., Kn với Ki Kj nếu i j đã được sắp xềp theo thứ tự tăng dần. viết chương trình thực hiện tìm


kiếm khoá có giá trị bằng X cho trước theo các phương pháp tìm kiếm tuần tự và tìm kiếm nhị phân. nếu tìm thấy thì cho biết vị trí cđa khoá trong dãy ngược lại trả về giá trị 0.

Ví dụ 3.15:

#include<iostream.h>

#include<conio.h>

#include<process.h> class search

{

protected: int *k; public:

virtual int find(int *a,int n,int x)

{

k = a; return 0;

}

search()

{

k=NULL;

}

~search()

{

delete k;

}

};

class sequential_search:public search

{

public:

virtual int find(int *a, int n, int x)

{

int i; i=1;


while((i<=n)&&(a[i]!=x)) i++; if(a[i]==x) return i;

else return 0;

}

};

class binary_search:public search

{

public:

virtual int find(int *a, int n, int x)

{

int l,r,m; l=1;r=n; while(l<=r)

{

m = (l+r) / 2; if(a[m]>x) r=m-1;

else if(a[m]<x) l=m+1; else return m;

}

return 0;

}

};

void main()

{

search *se[2]; int n,*a; clrscr();

cout<<"So phan tu n="; cin>>n;

a = new int[n]; if(a==NULL)

{

cout<<"Loi cap phat bo nho";


exit(1);

}

else

for(int i=1;i<=n;i++)

{

cout<<"Nhap toa do thu "<<i<<" :"; cin>>a[i];

}

cout<<"Day khoa da chon"; for(i=1;i<n;i++) cout<<a[i]<<", "; cout<<a[n];

sequential_search s_search; binary_search b_search;

int x;

cout<<"nNhap gia tri can tim x ="; cin>>x;

cout<<"nKet qua tim kiem tuan tu"; se[0] = &s_search;

cout<<"n"<<x<<" xuat hien o vi tri "<<se[0]->find(a,n,x)<<" trong day"; cout<<"nKet qua tim kiem nhi phan";

se[1] = &b_search;

cout<<"n"<<x<<" xuat hien o vi tri "<<se[1]->find(a,n,x)<<" trong day"; getch();

}


3.10.4. Liên kết động

Để quản lý một dãy các đối tượng cđa một lớp nào đó, ta có thể dùng cấu trúc mảng, tức là khai báo mảng đối tượng. Tuy nhiên, với cách tổ chức lưu trữ này có nhược điểm là hiệu quả sử dụng bộ nhớ không cao (như chúng ta đã phân tích ở một số môn học trước, chẳng hạn môn Cấu trúc dữ liệu và giải thuật). Một giải pháp khác cho vấn đề này là sử dụng liên kết động. Tức là, sử dụng danh sách móc nối, có thể nối đơn hoặc nối kép. Trước hềt ta định nghĩa lớp quản lý đối tượng, sau đó ta định nghĩa lớp (chẳng hạn tên lớp là node) tổ chức cấu trúc cđa một nút, đối với danh sách nối đơn, một nút sẽ gồm hai trường: trường info có


kiểu đối tượng, trường link là con trỏ đối tượng chứa địa chỉ nút tiếp theo trong danh sách. Đối với danh sách nối kép một nút có cấu trúc gồm 3 trường tương ứng với 3 thuộc tính: lptr, rptr, info.

Ví dụ 3.16:

Sử dụng danh sách nối đơn quản lý các đối tượng cđa lớp ts- thí sinh.

#include<iostream.h>

#include<conio.h>

#include<string.h>

#include<fstream.h> class ts

{

char sbd[5]; char ten[30];

unsigned int diem; public:

friend ostream &operator<<(ostream &os, const ts &t)

{

cout<<"nSo bao danh:"<<t.sbd; cout<<"nHo va ten:"<<t.ten; cout<<"nTong diem:"<<t.diem; return os;

}

friend istream &operator>>(istream &is,ts &t)

{

cin.ignore(1); cout<<"So bao danh:"; is.getline(t.sbd,5); cout<<"Ho va ten:"; is.getline(t.ten,30); cout<<"Tong diem:"; is>>t.diem; is.ignore();

return is;

..... Xem trang tiếp theo?
⇦ Trang trước - Trang tiếp theo ⇨

Ngày đăng: 03/07/2022