You are on page 1of 42

Lập trình hướng đối tượng với C++

Bài thực hành:


BÀI THỰC HÀNH SỐ 1
Mục tiêu:
+ Khởi động chương trình Turbo C++ (TC).
+ Tạo, biên dịch và thực hiện chương trình C++ .
+ Định nghĩa lớp và khai báo đối tượng.
+ Cách thức truy cập và thao tác trên các hàm thành viên và các biến thành viên của
lớp.
BÀI TẬP THỰC HÀNH
1. Khởi động chương trình Turbo C++
2. Tạo và biên dịch và thực hiện chương trình C++
3. Định nghĩa lớp và khai báo đối tượng
4. Cách thức truy cập và thao tác trên các hàm thành viên và các biến thành viên của lớp.
1. Khởi động chương trình Turbo C++
+ Để khởi động TC , bạn cần tìm và chạy tập tin TC.EXE. Thường thì tập tin này nằm
trong thư mục BIN trong thư mục cài đặt.
Vớ dụ : Bạn cài đặt Turbo C++ trong thu mục C:\TC khi đó để khởi động Turbo C++ bạn
tìm và chạy tập tin TC.EXE trong thư mục C:\TC\BIN.

Màn hình của chương trình TC


* Ghi chú : Để khởi động nhanh bạn có thể tạo shortcut cho chương trình. Khi đó để khởi động
TC bạn chỉ việc Double-Click vào biểu tượng của TC trên màn hình desktop.
2. Tạo và biên dịch và thực hiện chương trình C++
- Mở một file mới ( Menu File->New).
- Trong cửa sổ soạn thảo bạn Gõ vào đoạn chương trình sau:
#include <iostream.h>
#include <conio.h>
void main()
1.1 { 1.1
cout << "Hello world !";
getch();
}
- Lưu file vừa soạn thảo vào đĩa .(Menu File->Save hoặc phím nóng F2) .
- Nhấn tổ hợp phím CTRL - F9 để biên dịch và chạy chương trình. Kết quả như
hình sau

Màn hình kết quả khi thực thi chương trình


3. Định nghĩa lớp và khai báo đối tượng

Trang 1
Lập trình hướng đối tượng với C++

+ Phần này sẽ giúp các bạn hiểu được cách định nghĩa một lớp và khai báo một đối tượng của
lớp đó.
+ Thực hiện các bước sau:
+ Tạo một file mới.
+ Trong cửa sổ soạn thảo Gõ vào đoạn chương trình sau:
#include <iostream.h>
#include <conio.h>

class MyFirstClass // Dinh nghai lop


1.2
{
public :
int dataMember;
}; // Ket thuc dinh nghia lop

void main()
{
MyFirstClass aObject; // Khai bao mot doi tuong
aObject.dataMember = 50;
cout << "Du lieu cua doi tuong la: " << aObject.dataMember;
getch();
}
+ Lưu thành file FirstClass.CPP
+ Biên dịch và chạy chương trình, kết quả như sau:

Màn hình kết quả


+ Qua chương trình trên ta thấy định nghĩa của một lớp tương tự như định nghĩa của một record
chỉ thay từ khoá struct bằng từ khoá class và hoàn toàn tượng tự cho cách khai báo một đối tượng
của lớp
4. Cách thức truy cập và thao tác trên các hàm thành viên và các biến thành viên của lớp.
+ Phần này sẽ giỳp các bạn hiểu rõ hơn về các thành phần của lớp như hàm thành
viên(Member Functions) , biến thành viên (data members) cũng như cách khai báo và truy cập
lên các thành phần đó
+ Thực hiện các bước sau:
+ Tạo một file mới.
+ Trong cửa sổ soạnn thảo Gõ vào chương trình sau:
#include <iostream.h>
#include <conio.h>
1.3
Trang 2
Lập trình hướng đối tượng với C++

class CPoint // Dinh nghai lop diem


{
private : // Khai bao bien thanh vien, co thuoc tinh private
1.3
int x; // hoanh do
int y; // tung do

public : // Khai bao bien thanh vien, co thuoc tinh public


void Init(int cx, int cy); // ham khoi tao vi tri diem
void Display(); // Ham in vi tri cua diem
void Move(int dx, int dy); // Ham di chuyen vi tri

}; // Ket thuc dinh nghia lop

/* Phan mo ta (cai dat) cac ham thanh vien */

void CPoint :: Init(int cx, int cy)


{
x = cx;
y = cy;
}

void CPoint :: Display()


{
cout << "\n x:y = " << x <<":" << y;
}

void CPoint :: Move(int dx, int dy)


{
x += dx; // x = x + dx
y += dy; // y = y + dy
}

// Chuong trinh chinh

void main()
{
clrscr();
CPoint p1; // Khai bao 1 doi tuong cua lop CPoint
CPoint *p; // Khai bao mot con tro doi tuong CPoint

cout << "Toa do cua p1 sau khi goi p1.Init(10,10)";


p1.Init(10,10); // Khoi tao toa do diem
p1.Display(); // Thu hien thi xem sao !
p1.Move(1,1); // Sau di chuyen di mot chut
cout << "\nToa do cua p1 sau khi goi p1.Move(1,1)";
p1.Display(); // Xem da di chuyen chua ?

p = new CPoint; // Xin cap phat mot doi tuong CPoint


p->Init(100,100);

Trang 3
Lập trình hướng đối tượng với C++

cout << "\nToa do cua con tro p sau khi goi p->Init(100,100) :";
p->Display(); // hay nho, voi con tro phai la ->, khong phai "."
cout << "\nVa sau khi goi p->Move(10,10) ";
p->Move(10,10); // Chay mot doan nua roi hien thi
p->Display(); // Hien thi

cout << endl << endl << "An phim bat ky..." ;

getch();
}
+ Lưu file vào đĩa.
+ Kết quả khi chạy chương trình.

+ Ghi chú : Từ khoá public cho ta biết tầm vực của hàm hay biến được khai báo theo sau nó,ý
nghĩa của từ khoá này sẽ được làm rõ trong bài thực hành sau.
Bài tập làm thêm
Bài 1: Viết chương trình tính diện tích của hình chữ nhật và kiểm tra xem hình chữ nhật đó có
phải là hình vuụng hay không
Hướng dẫn: Định nghĩa một lớp hinh chữ nhật Rect như sau;
Class CRect // Lop hinh chu nhat
{
private :
int nWidth; // Chieu rong
int nHeight; // Chieu dai
public :
void Input(); // Nhap kich thuoc tu ban phim
void Init(int w, int h); // Khoi tao kich thuoc
long Area(); // Tra ve dien tich
int IsSquare(); // Co la hinh vuong khong.
] ; // Ket thuc phan dinh nghia (Khai bao) lop
+ Hàm Input cho phép người dùng nhập các chiều của hình chữ nhật từ bàn phím.
+ Hàm Init khởi tạo các chiều của hình chữ nhật với các giá tri w và h.
+ Hàm Area trả về diện tớch của hình vuụng.
+ Hàm IsSquare sẽ trả về 1 nếu hình chữ nhật là hình vuụng, nếu không thì trả về 0.
Bài 2: Viết chương trình tạo ra lớp phõn số, trong đó có các hàm thành viên cho phép nhập vào
phân số, khởi tạo phân số, kiểm tra tính hợp lệ của phân số, rút gọn phân số và in phân số ra màn
hình.
Bài 3: Xây dựng lớp "ngày" cho phép nhập vào một ngày, khởi tạo một ngày, kiểm tra ngày hợp
lệ, tớnh ngày tiếp theo, và in ngày ra màn hình.
Hướng dẫn: Định nghĩa lớp ngày như sau
Class CDate // Lop ngay
{
private :

Trang 4
Lập trình hướng đối tượng với C++

int nDay; // Ngay


int nMonth; // Thang
int nYear; // Nam

public :
void Input(); // Nhap ngay thang tu ban phim
void Init(int d, int m, int y);// Khoi tao gia tri
int IsValid(); // Kiem tra ngay xem co hop le ?
void NextDay(CDate &objNext); // Tinh ngay tiep theo
void Display();
Ư ; // Ket thuc phan dinh nghia (Khai bao) lop

Trang 5
Lập trình hướng đối tượng với C++

Bài thực hành:


BÀI THỰC HÀNH SỐ 2
Mục tiêu:
- Lớp (class) và đối tượng (object).
- Các thuộc tớnh dữ liệu và các hàm thành viên “public” và “private”.
- Mảng các đối tượng.
BÀI TẬP THỰC HÀNH
2.1 Lớp, đối tượng và các hàm thành viên
2.2 Mảng các đối tượng
2.1 Lớp, đối tượng và các hàm thành viên
2.1.1 Thành phần dữ liệu “public” trong lớp
Khi các thuộc tính được khai báo là “public” thì chúng có thể được truy xuất từ bên ngoài.
Chương trình sau minh hoạ điều này:
1. Tạo file mới
2. Gõ đoạn chương trình sau

#include <iostream.h>

class date
{
public:
int day;
int month;
int year;
};

void main()
{
date today;
today.day = 25;
today.month = 12;
today.year = 2001;
cout << “\n Ngay la “<< today.day<< “/” ;
cout << today.month << “/” << today.year << endl;
}

3. Lưu file với tên “date211.cpp”


4. Dịch và chạy chương trình

Kết quả trên màn hình là (nhấn tổ hợp phím Alt F5 để xem) :
Ngay la 25/12/2001

Trong chương trình trên, lớp date được cài đặt có ba thuộc tính được khai báo là public và
các thuộc tính này có thể được truy xuất từ bên ngoài lớp. Ở đây chúng được truy cập từ hàm
main(). Để truy xuất các thành phần của lớp, trong C++ sử dụng toán tử dấu chấm “.”;
Từ khoá endl dựng là ký tự xuống dòng hoặc làm cho đầy dòng, nó tương tự như ‘\n’.
5. Đóng file “date211.cpp”
2.1.2 Thành phần dữ liệu “private” trong lớp

Trang 6
Lập trình hướng đối tượng với C++

Khi không dựng từ khoá public thì trình biờn dịch C++ sẽ xem các thành phần của lớp được khai
báo là private. Các thành phần được khai báo là private sẽ không truy cập trực tiếp được từ bên
ngoài lớp.

1. Sửa lại file “date211.cpp”

#include <iostream.h>

class date
{ //mac đinh cac thanh phan se đuoc xem la private

int day;
int month;
int year;
};

void main()
{
date today;
today.day = 25;
today.month = 12;
today.year = 2001;
cout << “\n Ngay la “<< today.day<< “/” ;
cout << today.month << “/” << today.year << endl;
}

2. Lưu file (save as) với tên “date212.cpp”


3. Dịch chương trình, bạn sẽ thấy các thông báo lỗi sau:

date:: day is not accessible


date:: month is not accessible
date:: year is not accessible
Chương trình trên không thực hiện được vì các thuộc tớnh dữ liệu có khai báo là private do trình
biờn dịch mặc định hiểu như vậy khi không chỉ rõ là public hay là private. Để truy cập đến các
thuộc tính dữ liệu có khai báo là private bạn cần phải thông qua các hàm thành viên của lớp.
4. Đóng file “date212.cpp”

2.1.3 Sử dụng các hàm thành viên truy cập các thuộc tớnh dữ liệu “private”
Chương trình dưới đây minh hoạ việc sử dụng các hàm thành viên để truy cập các thuộc tính của
lớp.

1. Tạo file mới


2. Gõ đoạn chương trình sau

Trang 7
Lập trình hướng đối tượng với C++

#include <iostream.h>

class date
{
private:
int day;
int month;
int year;
public:
void getdate (void)
{
cout << “\n Nhap vao ngay (dd): “;
cin >> day;
cout << “\n Nhap vao thang (mm): “ ;
cin >> month;
cout << “\n Nhap vao nam (yy): “ ;
cin >> year;

} //ket thuc ham getdate

void display (void)


{
cout << “\n Ngay la “ << day << “/”;
cout << month << “/” << year << endl;

} // ket thuc ham display


};
void main()
{
date today;
today.getdate();
today.display();
}

3. Lưu file với tên “date213.cpp”


4. Dịch và chạy chương trình
Kết quả trên màn hình là (nhấn tổ hợp phím Alt F5 để xem) :

Nhap vao ngay (dd): 25


Nhap vao thang (mm): 12
Nhap vao nam (yy): 01
Ngay la 25/12/01

Trang 8
Lập trình hướng đối tượng với C++

Chương trình trên cài đặt lớp “date”có ba thuộc tính day, month, year kiểu số nguyên và
được khai báo là private, hai hàm getdate(), display() được định nghĩa ở trong lớp và được khai
báo là public, hai hàm này có thể được truy suất từ bên ngoài lớp.
Trong hàm main() có khai báo đối tượng (object) today có kiểu là date. Dùng toán tử dấu chấm
“.” để truy xuất các hàm, gọi today.getdate() để nhập dữ liệu cho đối tượng today, today.display()
để thể hiện trên màn hình. Như vậy, để truy xuất các thuộc tính có khai báo là private bạn phải
thông qua các hàm thành viên.

5. Đóng file “date213.cpp”

2.1.4 Truyền tham số đối tượng cho các hàm thành viên
1. Tạo file mới
2. Gõ đoạn chương trình sau

#include <iostream.h>

class Time
{
private:
int hours, minutes, seconds;
public:
void getinfo (void)
{
cin >> hours >> minutes >> seconds;
} //ket thuc ham getinfo
void display (void)
{
cout<<hours<<‘:’<<minutes<<‘:’<<seconds<< endl;
} // ket thuc ham display

void addit( Time aa, Time bb)


{
hours = aa.hours + bb.hours;
minutes = aa.minutes + bb.minutes;
seconds = aa.seconds + bb.seconds;

//kiem tra seconds < 60


if( seconds >= 60)
{
seconds -= 60; // seconds = seconds – 60
minutes++; //minutes = minutes + 1
}

//kiem tra minutes < 60


if (minutes >= 60)
{
minutes -=60;
hours++;
}
}

Trang 9
Lập trình hướng đối tượng với C++

};

void main()
{
Time one, two, three;
cout << “\n Nhap vao thoi gian mot (gio phut giay): ”;
one.getinfo();

cout << “\n Nhap vao thoi gian hai (gio phut giay): ”;
two.getinfo();

three.addit(one, two);
cout << “Ket qua la “;
three.display();
}

3. Lưu file với tên “time214.cpp”


4. Dịch và chạy chương trình
Chú ý khi nhập giờ phỳt giõy bạn phải nhập khoảng trắng giữa các giá trị.
Kết quả trên màn hình là (nhấn tổ hợp phím Alt F5 để xem) :

Nhap vao thoi gian mot (gio phut giay): 12 30 53


Nhap vao thoi gian hai (gio phut giay): 4 15 28
Ket qua la 16:46:21
Ngay la 25/12/01

Trong hàm main() ở chương trình trên có khai báo ba đối tượng của lớp Time là one, two,
three. Thông tin của đối tượng one, two được cung cấp thông qua gọi hàm getinfo của từng đối
tượng. Đối tượng three có được thông tin thông qua gọi hàm addit của nó, three.addit(one, two);
ở lời gọi hàm này, ta đó truyền hai đối tượng one và two vào cho hàm addit, trong hàm addit aa,
bb sẽ là các đối tượng đại diện cho one, two và các biến hours, minutes, seconds là các thuộc tính
của đối tượng three.

5. Đóng file “time214.cpp”

2.2 Mảng các đối tượng


Mảng các đối tượng cùng loại được sử dụng giống như mảng kiểu dữ liệu cơ sở. Chương trình
sau xây dựng lớp Student và sử dụng mảng Student trong chương trình chớnh.

1. Tạo file mới


2. Gõ đoạn chương trình sau

Trang 10
Lập trình hướng đối tượng với C++

#include <iostream.h>
class Student
{
private:
int rollno;
int marks;
public:
void getinfo ()
{
cout << “Nhap vao ma so sinh vien: “;
cin >> rollno ;
cout << “Nhap vao diem: “;
cin >> marks ;
} //ket thuc ham getinfo

void display ()
{
cout<<rollno<<‘\t’<<marks<< endl;
} // ket thuc ham display

int getmarks()
{
return marks;
} // ket thuc ham getmarks

};// ket thuc lop Student

void main()
{
Student stulist[100];
float total, average;
int no, i;

total = 0.0;
cout << “\n Nhap vao so luong sinh vien: ”;
cin >> no ;

for (i=0; i< no ; i++)


{
stulist[i].getinfo();
total = total + stulist[i].getmarks();
}

cout << “Ma so Diem”<< endl;


for (i=0; i< no; i++)
{
stulist[i].display();
}
average = total / no;
cout << “Diem trung binh cac sinh vien = ” << average;

Trang 11
Lập trình hướng đối tượng với C++

}// ket thuc ham main

3. Lưu file với tên “stu22.cpp”


4. Dịch và chạy chương trình
Kết quả trên màn hình là (nhấn tổ hợp phím Alt F5 để xem) :

Nhap vao so luong sinh vien: 3


Nhap vao ma so sinh vien: 1
Nhap vao diem: 13
Nhap vao ma so sinh vien: 2
Nhap vao diem: 15
Nhap vao ma so sinh vien: 3
Nhap vao diem: 19
Ma so Diem
1 13
2 15
3 19
Diem trung binh cac sinh vien = 15.666667
Trong chương trình trên có khai báo mảng 100 đối tượng Student là stulist[100]. Để truy xuất đối
tượng có vị trí thứ i ở trong mảng ta sử dụng stulist[i]. stulist[i].getinfo(); câu lệnh này gọi hàm
getinfo() của đối tượng ở vị trí i trong mảng. Chú ý mảng trong C++ có chỉ số bắt đầu từ 0.
Bài tập làm thêm
Viết chương trình quản lý học sinh với các chức năng sau:
Thờm một học sinh
Tìm thông tin các học sinh khi biết tờn.
Tìm học sinh có điểm trung bình cao nhất
Xoá học sinh ra khái danh sách.
In danh sách hoc sinh.
class Hocsinh
{
private:
int maso;
char hoten[30];
int toan, ly, hoa, van, su, dia, anhvan;
public:
void nhapthongtin(); //nhap thong tin cho hoc sinh
void hienthi(); //hien thi thong tin hoc sinh len man hinh
float diemtrungbinh();//lay diem trung binh cua hoc sinh
char *ten(); //lay ten cua hoc sinh
}

Trang 12
Lập trình hướng đối tượng với C++

Bài thực hành:


BÀI THỰC HÀNH SỐ 3
Mục tiêu:
• Constructors.
• Destructors.
• Hàm chồng (overloading).
• Hàm friend.
BÀI TẬP THỰC HÀNH
3.1. Constructors và destructors:
3.2. Constructors và destructors với cấp phát động:
3.3. Đa năng hóa hàm (hàm chồng):
4.4 Hàm friend:
3.1. Constructors và destructors:
Trong phần này các bạn sẽ viết một số chương trình trong đó có sử dụng các hàm constructors
(hàm khởi tạo) và destructors (hàm hủy) để làm rõ thêm về hai khái niệm này.
Khi một đối tượng được tạo, các thành viên của nó có thể được khởi tạo bởi một hàm
constructor. Hàm constructors sẽ được gọi một cách tự động để thực hiện công việc này mà không
phải gọi bất cứ hàm nào thuộc lớp. Cũng hoạt động giống như vậy, nhưng hàm destructors sẽ được
gọi tự động khi lớp bị hủy.
Trong chương trình dưới đây các bạn sẽ thấy cách mà các hàm constructors và destructors thực
thi. Chương trình sẽ sử dụng hàm constructor để khởi tạo một vùng hình chữ nhật thông qua hai
thuộc tính của nó là nWidth (chiều dài) và nHeight (chiều rộng).

#include <iostream.h>
#include <conio.h>
class CRectangle
{
private:
int nHeight; //chieu dai hinh chu nhat
int nWidth; //chieu rong hinh chu nhat
public:
CRectangle(); //ham constructor
int Area(); //ham tinh dien tich hinh chu nhat
void Initialize(int,int);
~CRectangle(); //ham destructor
};

CRectangle::CRectangle()
{
cout << "Khoi tao cac thuoc tinh bang ham constructor\n";
nHeight = 6;
nWidth = 8;
}

int CRectangle::Area()
{
return nHeight*nWidth;
}

Trang 13
Lập trình hướng đối tượng với C++

void CRectangle::Initialize(int Rong,int Dai)


{
cout << "khoi tao lai hinh chu nhat voi cac bien duoc dua vao\n";
nWidth = Rong;
nHeight = Dai;
}

CRectangle::~CRectangle()
{
cout << "destructor dang duoc goi\n";
}

void main()
{
clrscr();
CRectangle Box,Square;
cout << "Dien tich cua Box la: "<< Box.Area() << "\n";
cout << "Dien tich cua Square la: "<< Square.Area() << "\n";
Box.Initialize(12,8);
Square.Initialize(8,8);
cout << "Dien tich cua Box la: "<< Box.Area() << "\n";
cout << "Dien tich cua Square la: "<< Square.Area() << "\n";
}

Khi chạy chương trình trên chúng ta sẽ thu được kết quả như sau:
Khoi tao cac thuoc tinh bang ham constructor
Khoi tao cac thuoc tinh bang ham constructor
Dien tich cua Box la: 48
Dien tich cua Square la: 48
khoi tao lai hinh chu nhat voi cac bien duoc dua vao
khoi tao lai hinh chu nhat voi cac bien duoc dua vao
Dien tich cua Box la: 96
Dien tich cua Square la: 64
destructor dang duoc goi
destructor dang duoc goi
Chương trình trên khai báo một lớp tên là CRectangle. Trong lớp có 2 biến private kiểu integer.
Trong các hàm public có một hàm constructor và một hàm destructor. Hàm constructor thì có cùng
tên với tên lớp của nó. Hàm destructor được đặt tên cũng theo một cách như vậy nhưng có thêm
dấu ~ ở phía trước tên hàm đó.
Mỗi lần một đối tượng được tạo ra trong hàm main() thì hàm constructor của nó sẽ được thực hiện.
Trong hàm main() có khai báo hai đối tượng thuộc lớp CRectangle. Trong hàm constructor có đưa
vào lệnh để hiển thị dòng "Khoi tao cac thuoc tinh bang ham constructor" trên màn hình. Trong
hàm main khi ta vừa khai báo 2 đối tượng Box và Square thì các constructors của nó được gọi nên
ở màn hình output sẽ có hai dòng:
Khoi tao cac thuoc tinh bang ham constructor
Và diện tích của 2 hình chữ nhật này sẽ được tính dựa trên các giá trị đã được khởi tạo trong hàm
constructor (nWidth = 8,nHeight = 6). Khi đó diện tích của hai hình chữ nhật này là 48.
Sau đó chương trình sẽ gọi hàm Initialize() của Box và Square để gán lại giá trị mới cho các thuộc
tính nWidth, nHeight của từng đối tượng.

Trang 14
Lập trình hướng đối tượng với C++

Box.Initialize(12,8);
Square.Initialize(8,8);
Khi đó diện tích của Box và Square lần lượt là 96, 64. Vì các giá trị thuộc tính của 2 hình chữ
nhật này đã được gán lại với các giá trị khác nhau. Khi hàm Initialize() của Box và Square được
gọi thì màn hình output sẽ in ra màn hình 2 dòng:
khoi tao lai hinh chu nhat voi cac bien duoc dua vao
khoi tao lai hinh chu nhat voi cac bien duoc dua vao
Khi 2 đối tượng Box và Square bị hủy vào cuối hàm main, hàm destructor của các đối tượng
này sẽ được tự động thực thi. ở trong màn hình output chúng ta sẽ thấy 2 dòng sau, do 2 hàm
destructor được thực hiện:
destructor dang duoc goi
destructor dang duoc goi
Trong chương trình dưới đây, chúng ta sẽ viết một lớp với tên là CTime. Không giống như lớp
CRectangle ở trên trong lớp CTime còn có thêm một constructor khởi tạo các giá trị hours, minutes,
seconds của lớp CTime. Và qua đó các bạn sẽ thấy rõ hơn các hàm constructor được gọi khi với
tham số hoặc không có tham số. Và lớp này có một hàm destructor để gọi khi lớp bị hủy.
Các bạn tạo file và đánh vào chương trình sau:
#include <iostream.h>
#include <conio.h>

class CTime
{
private:
int nHours,nMinutes,nSeconds;
//bien luu gio, phut, giay cua lop CTime
public:
CTime(); //ham constructor khong doi so
CTime(int h,int m,int s);//ham constructor 3 doi so
void Display();
void AddIt(CTime Time1,CTime Time2);
~CTime(); //ham destructor
};

CTime::CTime()
{
cout << "ham constructor mac dinh\n";
nHours = nMinutes = nSeconds = 0;
}

CTime::CTime(int h,int m,int s)


{
cout << "ham constructor voi 3 doi so\n";
nHours = h;
nMinutes = m;
nSeconds = s;
}

void CTime::Display()
{
cout << nHours << ':' << nMinutes << ':' << nSeconds << endl;

Trang 15
Lập trình hướng đối tượng với C++

void CTime::AddIt(CTime Time1,CTime Time2)


{
nHours = Time1.nHours + Time2.nHours;
nMinutes = Time1.nMinutes + Time2.nMinutes;
nSeconds = Time1.nSeconds + Time2.nSeconds;
//kiem tra nSeconds > 60
if(nSeconds >= 60)
{
nSeconds -= 60;
nMinutes ++;
}
//kiem tra nMinutes > 60
if(nMinutes >= 60)
{
nMinutes -= 60;
nHours ++;
}
}

CTime::~CTime()
{
cout << "Ham destructor\n";
}

void main()
{
clrscr();
CTime Result;
CTime T1(1,49,50);
CTime T2(3,40,30);
Result.AddIt(T1,T2);
cout << "Ket qua la: ";
Result.Display();
}

Kết quả sau khi thực hiện chương trình trên là:
ham constructor mac dinh
ham constructor voi 3 doi so
ham constructor voi 3 doi so
Ham destructor
Ham destructor
Ket qua la: 5:30:20
Ham destructor
Ham destructor
Ham destructor
Trong chương trình trên, lớp CTime có đến 2 constructors để khởi tạo nó. Một constructor
thì không có đối số và một còn lại thì có 3 đối số.. Hàm constructor không có đối số là hàm
constructor mặc định sẽ được gọi. Trong hàm main(), biến Result, khi khai báo:

Trang 16
Lập trình hướng đối tượng với C++

CTime Result;
Thì hàm constructor sẽ được gọi cho đối tượng Result là constructor mặc định không có đối số. Vì
thế trong màn hình output chúng ta sẽ thấy xuất hiện dòng sau:
ham constructor mac dinh
Với hàm constructor mặc định này thì cả ba thuộc tính của lớp CTime là nHours, nMinutes,
nSeconds đều gán giá trị là 0. Khi đối tượng được khai báo như sau thì constructor còn lại sẽ được
gọi:
CTime T1(1,49,50);
CTime T2(3,40,30);
Khi khai báo hai đối tượng T1 và T2 chúng ta đưa vào cho Time1, Time2 ba đối số, khi đó hàm
constructor CTime(int,int,int) sẽ được gọi với 3 đối số là 3 giá trị chúng ta đưa vào. Vì hai đối
tượng được khai báo nên constructor sẽ được gọi lần lượt cho T1 và T2 nên chúng ta sẽ nhận được
tiếp theo 2 dòng sau trong màn hình output:
ham constructor voi 3 doi so
ham constructor voi 3 doi so
Hai dòng tiếp theo trong màn hình output chúng ta sẽ thấy hai dòng giống nhau là:
Ham destructor
Nếu như chỉ hiểu theo nghĩa là hàm destructor chỉ được gọi khi một đối tượng bị hủy thì chúng ta
thấy trong chương trình 3 đối tượng khai báo của chúng ta vẫn chưa bị hủy cho tới dòng lệnh tiếp
theo sau nó. Thật ra, trong chương trình của chúng ta có gọi hàm AddIt của đối tượng Result, với
2 đối số của nó là T1 và T2. Mà hàm destructor cũng sẽ được thực hiện tại cuối bất kỳ hàm nào
mà đối số của nó là một lớp hay một đối tượng nào đó được khai báo trong hàm. Đây chính là lý
do mà hai dòng hiển thị của hàm destructor hiện ra màn hình output. Và hàm destructor của lớp
CTime cũng sẽ được gọi 3 lần vào cuối hàm main(), vì khi đó 3 đối tượng Result, T1, T2 bị hủy.
Trong lớp CTime xuất hiện cùng một lúc hai hàm constructor với hai tham số khác nhau ta gọi đó
là đa năng hóa hàm constructor mà ta sẽ xét ở phần sau.

3.2. Constructors và destructors với cấp phát động:

Trong C++ toán tử new thường xuất hiện trong hàm constructors khi khởi tạo đối tượng.
Và vùng nhớ cấp phát này phải được xóa khi đốí tượng bị hủy, nên toán tử delete dùng để xóa
vùng nhớ được cấp phát bằng toán tử new thường được để trong hàm destructors.
Trong chương trình dưới đây chúng ta sẽ xây dựng một lớp mà thuộc tính của nó là một chuỗi.
Trong hàm constructor của lớp này chúng ta sẽ sử dụng toán tử new để cấp phát vùng nhớ cho
chuỗi này. Trong hàm destructor của lớp chúng ta sẽ dùng toán tử delete để xóa vùng nhớ này đi.
Các bạn hãy mở một file mới và đánh vào đó chương trình sau:
#include <iostream.h>
#include <conio.h>
#include <string.h>
class CString
{
private:
char* strName;
public:
CString(char* str)
{
int size = strlen(str);
strName = new char[size + 1];
strcpy(strName,str);
}

Trang 17
Lập trình hướng đối tượng với C++

void Display()
{
cout << strName << endl;
cout<<"Chieu dai cua chuoi = "<<strlen(strName)<< endl;
}
~CString()
{
delete []strName;
}
};
void main()
{
clrscr();
CString strFirst("Chao cac ban");
CString strSecond("Chao tam biet");
strFirst.Display();
strSecond.Display();
}

Và khi chương trình được chạy nó sẽ cho kết quả ở màn hình output như sau:

Chao cac ban

Chieu dai cua chuoi = 12

Chao tam biet


Chieu dai cua chuoi = 13
Trong chương trình trên lớp CString chỉ có một thuộc tính, một con trá kiểu char, có tên là
strName. Con trá này sẽ trá đến một chuỗi có chiều dài động mỗi khi đối tượng được tạo.
Hàm constructor lấy một đối số là chuỗi sẽ được gán cho biến strName của lớp CString và biến
này sẽ được cấp phát một vùng nhớ bằng toán tử new có kích thước đúng bằng với kích thước của
đối số được đưa vào hàm constructor của lớp. Hàm Display của lớp CString dùng để hiển thị chuỗi
strName và độ dài của nó ra màn hình. Trong hàm destructor chương trình sẽ dùng toán tử delete
để xóa đi vùng nhớ đã được cấp phát cho biến strName.
3.3. Đa năng hóa hàm (hàm chồng):
Trong phần này chúng ta sẽ viết một chương trình mà trong đó có nhiều hàm cùng tên với nhau,
nhưng nó khác nhau về số đối số hay kiểu của các đối số đó. Các hàm như vậy được gọi là các
hàm chồng nhau. Các đối số sẽ là sự phân biệt khác nhau để biết hàm nào được gọi, kiểu trả về
của hàm không được dùng để phân biệt các hàm này.
Chương trình dưới đây sẽ khai báo một lớp CWords trong đó nó có các thuộc tính là số nguyên và
một chuỗi ký tự.
Mở file và nhập vào chương trình sau đây:
#include <iostream.h>
#include <conio.h>
#include <string.h>
class CWords
{
private:
int nNum;

Trang 18
Lập trình hướng đối tượng với C++

char strTitle[20];
public:
CWords()
{
nNum = 0;
strcpy(strTitle," ");
}
void Display(int i)
{
nNum = i;
cout << "Tham so la " << nNum << endl;
cout << "Day khong phai la chuoi" << endl;
}
void Display(char c)
{
strTitle[0] = c;
cout << "Tham so la " << strTitle[0] << endl;
cout << "Day la mot ky tu" << endl;
}
void Display(char* str)
{
strcpy(strTitle,str);
cout << "Tham so la " << strTitle << endl;
cout << "Day la mot chuoi" << endl;
}
void Display(char* str,int i)
{
strcpy(strTitle,str);
nNum = i;
cout<<"Tham so la "<<strTitle<<"and"<<nNum<<endl;
cout << "Day la mot chuoi" << endl;
}
};
void main()
{
clrscr();
CWords X;
X.Display(120);
X.Display('A');
X.Display("String");
X.Display("String",10);
}

Khi biên dịch chương trình trên và thực hiện nó ta được kết quả như sau:
Tham so la 120
Day khong phai la chuoi
Tham so la A
Day la mot ky tu
Tham so la String
Day la mot chuoi

Trang 19
Lập trình hướng đối tượng với C++

Tham so la Stringand 10
Day la mot chuoi
Trong chương trình này lớp CWords được định nghĩa với một constructor và một hàm chồng
Display(). Trong hàm main, khai báo một đối tượng X thuộc lớp CWords và hàm Display của nó
được gọi với các tham số khác nhau.
Với các đối số được đưa vào trong hàm khác nhau đó nó sẽ tương ứng với từng hàm Display đã
được khai báo trong lớp. Với tham số nào thì sử dụng hàm có đối số tương ứng đó.
X.Display(120);
X.Display('A');
X.Display("String");
X.Display("String",10);
Như hàm Dislay được gọi đầu tiên là hàm chỉ có duy nhất một đối số kiểu int, còn hàm Display
gọi kế tiếp là hàm Display mà đối số của nó có kiểu char, tiếp theo đó là hàm có đối số kiểu con
trá char, còn hàm cuối cùng có hai đối số là kiểu chuổi và kiểu số nguyên.

4.4 Hàm friend:

Một hàm có thể được định nghĩa như là một hàm friend của một lớp để có thể truy cập các
thuộc tính private của lớp đó. Một constructor và destructor của một lớp không thể là một hàm
friend.
Trong chương trình dưới đây, chúng ta sẽ sử dụng một hàm friend để cộng hai biến kiểu float
thuộc về hai lớp khác nhau là Alpha và Beta. Hàm friend là một hình thức cầu nối giữa hai lớp
khác nhau để truy cập các thuộc tính private của 2 lớp này.

#include <iostream.h>
#include <conio.h>
class Beta;
class Alpha
{
private:
float X;
public:
Alpha()
{
X = 5.0;
}
friend float Init(Alpha,Beta);
};

class Beta
{
private:
float Y;
public:
Beta()
{
Y = 1.0;
}
friend float Init(Alpha,Beta);
};

Trang 20
Lập trình hướng đối tượng với C++

float Init(Alpha A,Beta B)


{
return A.X + B.Y;
}
void main()
{
clrscr();
Alpha A;
Beta B;
cout << Init(A,B) << " la ket qua cua hai lop\n";
}
Khi chạy chương trình trên chúng ta sẽ được kết quả như sau:
6 la ket qua cua hai lop
ở chương trình trên trên chúng ta sử dụng cả hai lớp Alpha và Beta. ở hai lớp này đều có hàm
constructor để khởi tạo giá trị cho các thuộc tính của lớp đó, là biến X ở lớp Alpha và Y ở lớp
Beta. Vì lớp Alpha khai báo trước lớp Beta thì để trong lớp Alpha có thể truy cập đến lớp Beta ta
phải khai báo lớp Beta phía trên:
class Beta
Nếu chúng ta không khai báo lớp Beta phía trên thì trong hàm Init của lớp Alpha không thể khai
báo đối số thuộc lớp Beta.
Hàm friend Init lấy hàm tham số, tham số thứ nhất là lớp Alpha và tham số thứ hai lớp Beta. Hàm
friend này không thuộc về lớp nào. Vì thế khi khao báo nó chúng ta không phải đưa ra nó thuộc
về lớp nào. Vì là hàm friend của cả hai lớp Alpha và Beta nên nó có thể truy cập đến biến private
X của lớp Alpha, và Y của lớp Beta.
Một chú ý là hàm friend phải định nghĩa bên ngoài hay khác hơn nó không thuộc bất cứ lớp nào.

Bài tập làm thêm

Bài 1: Viết một chương trình khai báo lớp CString, tương tự như lớp CString đã viết trong bài
nhưng thêm một số tính năng sau:
Hàm Overwrite
void Overwrite(int c,int nPos);
//thay thế ký tự thứ nPos trong chuỗi bằng ký tự c
void Overwrite(char* str,int nPos);
//thay thế ký các ký tự trong chuỗi strNam từ vị trí nPos đến vị trí (nPos +
//strlen(str) " 1) bằng chuỗi str;
Một hàm constructor mặc định với chuỗi strName là rỗng.
Hàm Insert cũng hai hàm giống như hàm Overwrite nhưng là chèn tại vị trí nPos.
Vd: Insert("c",2); AABB -> AcABB
Insert("CC",2); AABB -> ACCABB

Bài 2: Viết một chương trình khai báo hai lớp CCircle và CRectangle. Hai lớp này có một hàm
friend Area để tính tổng diện tích của hai hình này, hàm này được khai báo như sau:
friend int Area(CCircle,CRectangle);

Trang 21
Lập trình hướng đối tượng với C++

Bài thực hành:


BÀI THỰC HÀNH SỐ 4
Mục tiêu:
Đa năng hoá các toán tử.
Đa năng hoá toán tử gán.
Khởi tạo chép đối tượng.
Chuyển đổi kiểu với kiểu do người dùng định nghĩa.
BÀI TẬP THỰC HÀNH
4.1 Đa năng hoá toán tử
4.2 Đa năng hoá toán tử gán và khởi tạo chép đối tượng
4.3 Chuyển đổi kiểu với kiểu người dùng định nghĩa
4.1 Đa năng hoá toán tử
Các toán tử ++, --, <= , > +=, có thể đa năng hoá cho các kiểu dữ liệu người dùng định nghĩa
như các lớp đối tượng. Các toán tử một ngôi và toán tử hai ngôi có thể đa năng hoá như sau:
4.1.1 Toán tử một ngụi (Unary Operators)
Chương trình sau sẽ đa năng hoá các toán tử ++ và --. Toán tử ++ chuyển các ký tự trong
chuỗi ký tự thành các ký tự hoa, toán tử -- chuyển các ký tự trong chuỗi ký tự thành các ký tự
thường.

1. Tạo file mới


2. Gõ đoạn chương trình sau

#include <iostream.h>
#include <string.h>
#include <conio.h>

class Converter
{
private:
char str[80];
public:
Converter()
{
strcpy(str,””);
}
Converter(char *s)
{
strcpy(str,s);
}
void display()
{
cout <<str<< endl;
}
Converter operator ++() //dạng tiền tố
{
return (strupr(str));
}
Converter operator ++(int) //Hậu tố

Trang 22
Lập trình hướng đối tượng với C++

{
Converter ss = str;
char *ptr = strupr(str);
strcpy (str, ptr);
return ss;
}
Converter operator -- () //dạng tiền tố
{
return (strlwr(str));
}
Converter operator --(int) //Hậu tố
{
Converter ss = str;
char *ptr = strlwr(str);
strcpy(str,ptr);
return ss;
}
};

void main()
{
clrscr();
Converter s1 = “changed to UPPERCASE”;
Converter s2 = “BACK TO LOWER CASE”;
Converter s3 = “that is all for now”;
Converter s4 = “ENDING ON A LOW NOTE”;
Converter s5;

int i, j;

++s1;
cout << “++s1 = “;
s1.display();
--s2;
cout<<”++s1 = “;
s2.display();
s5 = s3++;
cout << “Result of s5 = s3++ “<< endl << “s3 = “;
s3.display();
cout<<”s5 = “;
s5.display();
s4--;
cout<<”s4-- = “;
s4.display();
}

3. Lưu file với tên “danag411.cpp”


4. Dịch và chạy chương trình

Kết quả trên màn hình là (nhấn tổ hợp phím Alt F5 để xem) :

Trang 23
Lập trình hướng đối tượng với C++

++s1 = CHANGED TO UPPERCASE


++s1 = back to lower case
Result of s5 = s3++
s3 = THAT IS ALL FOR NOW
s5 = that is all for now
s4-- = ending on a low note

Trong chương trình trên chúng ta xây dựng lớp Converter có một thành phần dữ liệu là mảng ký
tự. Chúng ta khai báo file string.h để sử dụng các hàm chuẩn về chuỗi.
Chúng ta sử dụng các hàm chuẩn về chuỗi: strupr() để chuyển chuỗi ký tự thành chuỗi ký tự hoa,
strlwr() để chuyển các chuỗi ký tự thành các chuỗi ký tự thường.
Để trình biờn dịch phõn biệt được các toán tử ++, -- đứng trước hay là đứng sau, chúng ta sử dụng
có pháp sau:

operator++(); //dạng tiền tố operation


xác định toán tử đứng trước

operator++(int); //Hậu tố operation


xác định toán tử đứng sau. Tham số int chỉ là giả để trình biờn dịch phõn biệt hai
hình thức trên.
Trong cõu lệnh s5 = s3++ thì lệnh s5 = s3 sẽ thực hiện trước rồi đến lệnh s3++. Vì
vậy kết quả in ra màn hình là:

s3 = THAT IS ALL FOR NOW


s5 = that is all for now

5. Đóng file “danag411.cpp”

4.1.2 Toán tử hai ngụi (Binary Operators)


Khi đa năng hoá toán tử hai ngôi, thành phần bên phải toán tử là tham số, thành phần bên trái
toán tử là đối tượng thực hiện hàm.
Trong chương trình dưới đây, chúng ta sẽ đa năng hoá toán tử +=. Toán tử này kết hợp phép gán
và phép cộng. Trong lệnh sau s3 = s1 += s2, s3 bằng s1 và có kết quả là s1 cộng với s2.

1. Tạo file mới


2. Gõ đoạn chương trình sau

#include <iostream.h>
#include <string.h>
#include <conio.h>
const SIZE = 80;
class CPhrase
{
private:
char str[SIZE];
public:
CPhrase() //constructors
{

Trang 24
Lập trình hướng đối tượng với C++

strcpy(str,””);
}
CPhrase(char *s)
{
strcpy(str,s);
}
void display()
{
cout<<str<<endl;
}
CPhrase operator +=(CPhrase aa) //overloaded +=
{
if (strlen(str) + strlen(aa.str)<SIZE)
{
strcat(str,aa.str);
return (*this);
}
else
{
cout<<”string is too long”;
return (*this);
}
}
};

void main()
{
clrscr();
CPhrase s1;
CPhrase s2 = “ Chao cac ban”;
s1+=s2;
s1.display();
s1 = “ Chuc suc khoe”;

CPhrase s3;
s3 = s1 += s2;
s3.display();

CPhrase s4;
CPhrase s5 = “ Xin moi vao”;
s4 = s2 += s5 += s5;
s4.display();
}
3. Lưu file với tên “danag412.cpp”
4. Dịch và chạy chương trình
Kết quả trên màn hình là (nhấn tổ hợp phím Alt F5 để xem) :

Chao cac ban


Chuc suc khoe Chao cac ban
Chao cac ban Xin moi vao Xin moi vao

Trang 25
Lập trình hướng đối tượng với C++

Nếu bạn chỉ sử dụng lệnh đơn giản là s1 += s2; thì trong hàm không cần trả về giá trị.
Tuy nhiên để có được lệnh phức tạp hơn như s3 = s1 +=s2, s4 = s2 += s5 += s5 phải
có kiểu trả về.
4.2 Đa năng hoá toán tử gán và khởi tạo chép đối tượng
Xây dựng lớp CString như sau:

1. Tạo file mới


2. Gõ đoạn chương trình sau

#include <iostream.h>
#include <string.h>
#include <conio.h>

class CString
{
private :
char* str;
public:
CString (char* s=””) //constructor
{
int size = strlen(s);
str = new char[size+1];
strcpy(str, s);
}

CString (CString &ss) // copy constructor


{
str = new char[strlen(ss.str) + 1];
strcpy(str, ss.str);
}
~CString() //destructor
{
delete str;
}
CString&operator = (CString& ss) //toán tử gán
{
delete str;
str = new char[strlen(ss.str) + 1];
strcpy(str, ss.str);
return *this;
}
void showstring()
{
cout << str<<endl;
}
};
void main()
{
clrscr();
CString s1 = “ Chao cac ban”;

Trang 26
Lập trình hướng đối tượng với C++

cout <<”s1 = “;
s1.showstring();
CString s2(s1), s3;
s3 = s1;
cout << “s2 = “;
s2.showstring();
cout << “s3 = “;
s3.showstring();
CString s4 = s1;
cout << “s4 = “;
s4.showstring();
}

3. Lưu file với tên “con42.cpp”


4. Dịch và chạy chương trình
Kết quả trên màn hình là (nhấn tổ hợp phím Alt F5 để xem) :

s1 = Chao cac ban


s2 = Chao cac ban
s3 = Chao cac ban
s4 = Chao cac ban

4.3 Chuyển đổi kiểu với kiểu người dùng định nghĩa

Chuyển đổi kiểu qua lại giữa kiểu cơ vản và kiểu đối tượng.
1.Tạo file mới
2.Gõ đoạn chương trình sau

#include <iostream.h>
#include <string.h>
#include <conio.h>
const SIZE = 80;
class CString
{
private:
char str[SIZE];
public:
CString ()
{
strcpy(str,””);
}
CString (char *s)
{
strcpy (str,s);
}
void getstr()
{
cout<< “Nhap vao chuoi: “;
cin >>str;
}

Trang 27
Lập trình hướng đối tượng với C++

void display()
{
cout <<str<<endl;
}
operator char*()
{
return (str);
}
};
void main()
{
clrscr();
CString s1;
char* p;
s1.getstr();
s1.display();
p = s1;
cout << “Chuoi p = “<<p <<endl;
char n[15] = “Chuoi moi”;
s1 = n;
s1.display();
}

3. Lưu file với tên “con42.cpp”


4. Dịch và chạy chương trình
Kết quả trên màn hình là (nhấn tổ hợp phím Alt F5 để xem) :
Nhap vao chuoi: hello
hello
Chuoi p = hello
Chuoi moi

Trong hàm main(), cõu lệnh sau:

p = s1;

gán cho con trá kiểu ký tự p đối tượng s1. Khi trình biờn dịch thấy vế phải của phép gán là đối
tượng và vế trái là con trá ký tự thì nó sử dụng hàm chuyển kiểu.
s1 = n;
lệnh này trình biờn dịch tự động gọi hàm khởi tạo có một tham số, nếu hàm khởi tạo không được
định nghĩa thì trình biờn dịch sẽ báo lỗi.

Trang 28
Lập trình hướng đối tượng với C++

Bài tập làm thêm

Xây dựng lớp “ngày” có cài đặt các toán tử ++, -- để tăng lên, giảm xuống 1 ngày.

Trang 29
Lập trình hướng đối tượng với C++

Bài thực hành:


BÀI THỰC HÀNH SỐ 5
Mục tiêu:
- Đơn kế thừa
- Đa kế thừa.
BÀI TẬP THỰC HÀNH
5.1 Đơn kế thừa (kế thừa đơn)
5.1 Đơn kế thừa (kế thừa đơn)
Chúng ta sử dụng kế thừa trong lập trình hướng đối tượng để có thể sử dụng lại các chức năng
của các lớp khác. Các thành phần của lớp dẫn xuất chỉ có thể truy xuất đến các thành phần của
lớp cơ sở có khai báo là public và protected.

1. Tạo file mới


2. Gõ đoạn chương trình sau

#include <iostream.h>
#include <conio.h>
class vehicle
{
protected:
int wheels;
double weight;
public:
void initialise(int whls, double wght);
int get_wheels()
{
return wheels;
}
double get_weight()
{
return weight;
}
double wheel_loading()
{
return weight/wheels;
}
};

class car: public vehicle


{
private:
int passenger_load;
public:
void initialise(int whls, double wght, int people = 4);
int passengers()
{
return passenger_load;
}
};

Trang 30
Lập trình hướng đối tượng với C++

class truck: public vehicle


{
private:
int passenger_load;
double payload;
public:
void init_truck(int number = 2, double max_load = 24000.0);
double efficiency();
int passengers()
{
return passenger_load;
}
};

//initialise to any data desired


void vehicle::initialise(int whls, double wght)
{
wheels = whls;
weight = wght;
}

void car:: initialise(int whls, double wght, int people)


{
passenger_load = people;
wheels = whls;
weight = wght;
}

void truck:: init_truck(int number, double max_load)


{
passenger_load = number;
payload = max_load;
}

double truck::efficiency()
{
return payload/(payload + weight);
}

void main()
{
clrscr();
vehicle bicycle;
bicycle.initialise(2,25);
cout << “Xe dap co “<<bicycle.get_wheels() << ”banh xe. \n”;
cout << “Khoi dong banh xe ”<< bicycle.wheel_loading()
<< “don vi khoi luong tren mot banh xe. \n”;
cout<<”Khoi luong cua xe la ”<<bicycle.get_weight()
<<”don vi khoi luong. \n\n”;

Trang 31
Lập trình hướng đối tượng với C++

car c;
c.initialise(4,1500.0,5);
cout<<”Chiec xe o to cho duoc “<<c.passengers()<<” hanh khach.\n”;
cout<<”Chiec xe o to nang “<<c.get_weight()
<<”don vi khoi luong.\n”;
cout<<”Khoi dong banh xe “<<c.wheel_loading()
<< “don vi khoi luong tren mot banh xe. \n\n”;

truck v;
v.initialise(18,7000.0);
v.init_truck(1,15000.0);
cout<<”Xe tai nang “<<v.get_weight()<<” don vi khoi luong.\n”;
cout<<”Su hieu qua cua xe: ”<< 100.0*v.efficiency()
<<” phan tram.\n”;
}

3. Lưu file với tên “single51.cpp”


4. Dịch và chạy chương trình
Kết quả trên màn hình là (nhấn tổ hợp phím Alt F5 để xem) :

Xe dap co 2 banh xe.


Khoi dong banh xe 12.5 don vi khoi luong tren mot banh xe.
Khoi luong cua xe la 25 don vi khoi luong.

Chiec xe o to cho duoc 5 hanh khach.


Chiec xe o to nang 1500 don vi khoi luong.
Khoi dong banh xe 375 don vi khoi luong tren mot banh xe.

Xe tai nang 7000 don vi khoi luong.


Su hieu qua cua xe: 68.181818 phan tram

5. Đóng file “danag411.cpp”

Trong chương trình trên lớp vehicle có hai thành phần dữ liệu có khai báo là protected, và
nhiều hàm có khai báo là public. Lớp vehicle là lớp cơ sở của hai lớp car và truck. Chúng ta
thấy trong hai lớp này có truy xuất đến lớp cơ sở.

a. Đa kế thừa.

Đa kế thừa được sử dụng khi một lớp muốn kế thừa từ nhiều lớp cơ sở.

1. Tạo file mới


2. Gõ đoạn chương trình sau

Trang 32
Lập trình hướng đối tượng với C++

#include <iostream.h>
#include<iomanip.h>
#include<conio.h>

class person_data //one base class


{
private:
char name[25];
int roll_no;
char sex;
public:
void getinfo();
void display();
};

class academics //second base class


{
private:
char course_name[25];
int semester;
char grade[3];
public:
void getinfo();
void display();
};

class stud_scholarship: public person_data, public academics


{
private:
float amount;
public:
void getinfo();
void display();
};

void person_data::getinfo()
{
cout << “Ten: “;
cin>> name;
cout<<”So: “;
cin>>roll_no;
cout<<”Gioi tinh(F/M) : “;
cin>> sex;
}

void person_data:: display()


{
cout<<name<<”\t”;
cout<<roll_no<<”\t”;
cout<<sex<<”\t”;

Trang 33
Lập trình hướng đối tượng với C++

void academics::getinfo()
{
cout<<”Ten khoa (BA/MBA/MCA etc)? “;
cin>>course_name;
cout<< “Hoc ky (1/2/3/...)? “;
cin>>semester;
cout<<”muc do (A,B,B+,B-..) ? ”;
cin>>grade;
}

void academics::display()
{
cout<<course_name<<”\t”;
cout<<semester<<”\t”;
cout<<grade<<”\t”;
}

void stud_scholarship::getinfo()
{
person_data::getinfo();
academics::getinfo();
cout<<”Su ho tro “;
cin>>amount;
}
void stud_scholarship::display()
{
person_data::display();
academics::display();
cout<<setprecision(2);
cout<<amount<<endl;
}

void main()
{
clrscr();
stud_scholarship obj;
cout<<”Nhap cac thong tin sau: “<<endl;
obj.getinfo();
cout<<endl;
cout<<”Ten So Gioi tinh Khoa Hoc ky Muc do”;
cout<<”Amount”<<endl;
obj.display();
}

3. Lưu file với tờn “multi52.cpp”


4. Dịch và chạy chương trình
5. Đóng file “danag411.cpp”

Trang 34
Lập trình hướng đối tượng với C++

Trong chương trình trên, các lớp cơ sở có hàm trùng tên vì vậy khi lớp dẫn xuất gọi các hàm
này phải chỉ rõ là hàm dược gọi của lớp nào (xem hàm getinfo và hàm display của lớp dẫn
xuất).

b. Hàm khởi tạo trong kế thừa


Khi trong lớp cơ sở và lớp dẫn xuất có hàm khởi tạo (constructors) thì lớp cơ sở sẽ được khởi
tạo trước với hàm khởi tạo mặc định hoặc hàm có tham số tùy thuộc vào khai báo ở trong lớp
dẫn xuất.

1. Tạo file mới


2. Gõ đoạn chương trình sau

#include<iostream.h>
#include<conio.h>
class Alpha
{
public:
Alpha()
{
cout<< “Ham khoi tao cua lop Alpha”<<endl;
}
};

class Beta:public Alpha


{
public:
Beta():Alpha()
{
cout<< “Ham khoi tao cua lop Beta, ke thua tu lop Alpha”
<<endl;
}
};

class Gamma: public Alpha


{
public:
Gamma():Alpha()
{
cout<< “Ham khoi tao lop Gamma, ke thua thu lop Alpha”
<<endl;
}
};
class Delta: public Gamma, public Beta
{
Beta b; //base class object
public:
Delta():Gamma(),Beta()
{
cout<< “Ham khoi tao lop Delta, ke thua thu lop Beta ”
<< “va lop Gamma, \n”

Trang 35
Lập trình hướng đối tượng với C++

<< “co mot doi tuong Beta o trong “


<<endl;
}
};

void main()
{
clrscr();
cout<<”Khai bao mot doi tuong cua lop Alpha \n”;
Alpha aa;
cout<<endl;

cout<<”Khai bao mot doi tuong cua lop Beta \n”;


Beta bb;
cout<<endl;

cout<<”Khai bao mot doi tuong cua lop Gamma \n”;


Gamma cc;
cout<<endl;

cout<<”Khai bao mot doi tuong cua lop Delta \n”;


Delta dd;
cout<<endl;
}

3. Lưu file với tên “multi53.cpp”


4. Dịch và chạy chương trình
Màn hình kết quả như sau:

Khai bao mot doi tuong cua lop Alpha


Ham khoi tao cua lop Alpha

Khai bao mot doi tuong cua lop Beta


Ham khoi tao cua lop Alpha
Ham khoi tao cua lop Beta, ke thua tu lop Alpha

Khai bao mot doi tuong cua lop Gamma


Ham khoi tao cua lop Alpha
Ham khoi tao lop Gamma, ke thua thu lop Alpha

Khai bao mot doi tuong cua lop Delta


Ham khoi tao cua lop Alpha
Ham khoi tao lop Gamma, ke thua thu lop Alpha
Ham khoi tao cua lop Alpha
Ham khoi tao cua lop Beta, ke thua tu lop Alpha
Ham khoi tao cua lop Alpha
Ham khoi tao cua lop Beta, ke thua tu lop Alpha
Ham khoi tao lop Delta, ke thua thu lop Beta va lop Gamma,
co mot doi tuong Beta o trong

Trang 36
Lập trình hướng đối tượng với C++

5. Đóng file “danag411.cpp”


Trong chương trình trên các bạn sẽ thấy được thứ tự các hàm khởi tạo được gọi như thế
nào.

Trang 37
Lập trình hướng đối tượng với C++

Bài thực hành:


BÀI THỰC HÀNH SỐ 6
Mục tiêu:
+ Thực hành cách viết chương trình có sử dụng cơ chế đa hình(polymorphism).
+ Làm rõ các khái niệm: hàm ảo, hàm thuần ảo, và hàm hủy ảo (Virtual destructor).
BÀI TẬP THỰC HÀNH
6.1 Cơ chế đa hình (Polymorphism).
6.2 Hàm ảo (Virtual functions).
6.3 Hàm thuần ảo.
6.4 Hàm hủy ảo(Virtual destructors).
6.1 Cơ chế đa hình (Polymorphism).
Cơ chế đa hình trong C++ là cơ chế cho phép hành vi đối tượng có thể có nhiều thể hiện khác
nhau tùy thuộc vào lớp thực chất mà đối tượng đó thuộc về. Khả năng cho phép một chương trình
sau khi đó biờn dịch có thể có nhiều diễn biến xảy ra là một trong những thể hiện của tớnh đa hình
– tớnh muụn màu muụn vẻ – của chương trình hướng đối tượng, một thông điệp được gởi đi (gởi
đến đối tượng) mà không cần biết đối tượng nhận thuộc lớp nào. Để thực hiện được tính đa hình,
các nhà thiết kế C++ cho chúng ta dựng cơ chế kết nối động (dynamic binding) thay cho cơ chế
kết nối tĩnh (static binding) ngay khi chương trình biờn dịch được dùng trong các ngôn ngữ cổ
điển như C, Pascal,
6.2 Hàm ảo (Virtual functions).
Hàm ảo là hàm phải được mô tả trong lớp cơ bản, Trước hàm ảo phải có từ khoá virtual. Ta xột
vớ dụ sau:

#include <iostream.h>
#include <string.h>
#include <conio.h.>
class person
{
protected:
char *name;
public:
person(char *n) { name = n;}
virtual void print() // hàm ảo
{
cout << “My name is :”<<name << endln;
}
};
class foreigner : public person
{
public:
foreigner(char *n) : person(n) { }

void printf()
{
cout <<ll mio nome e” <<name <<endln;

}
};
class alien : public person

Trang 38
Lập trình hướng đối tượng với C++

{
public:
alien(char *n) :person(n){ }
void print()
{
cout <<”&*^*&%& **^@<<name<<endln;
cout << sorry, there’s a communication problem”;
}

};
void main()
{
clrscr();
person* p1;
person *p2;
p1 = new person(“Jack”);
p2 = new foreigner(“Maria”);
cout <<”Introducing a Person:” <<endln;
p1->print();
cout <<”Introducing a Foreigner:” <<endln;
p2->print();

p1 = new foreigner(“Al Pacino”);


cout << “Reintroducing the Person:” << endln;
p1 ->print();
person* p3;
p3 = new alien(“Martian”);
cout << “Introducing a alien:” << endln;
p3 ->print();

Kết quả sau khi chạy chương trình:

Introducing the Person:


My name is Jack
Introducing the Foreiger:
ll mi o nome a Maria

Reintroducing the person:


ll mio nome e Al Pacino
Introducing the alien:
&*^*&%& **^@ Martian
Sorry there’s a communication problem

Trong vớ dụ trên ta thấy cả hai lớp dẫn xuất đều có hàm print như trong lớp cơ bản của
chúng, hàm print trong lớp person là một hàm ảo. Ban đầu cả hai con trá p1 và p2, p3 đếu
có kiểu person nhưng sau đó p1 lại thực sự trá đến một đối tượng kiểu person trong khi p2
lại trá đến một đối tượng kiểu foreigner và p3 trá đến đối tượng kiểu alien. Khi thực hiện

Trang 39
Lập trình hướng đối tượng với C++

p2 không gọi hàm print của lớp person mà gọi hàm print của lớp foreigner , và p3 gọi hàm
print của lớp alien. Đây chính là cơ chế đa hình mà ta đó nói ở trên.
6.3 Hàm thuần ảo.
Hàm thuần ảo là hàm ảo được mô tả bằng cách gán giá trị 0 cho hàm. Một lớp được gọi là
lớp trõu tượng nếu trong lớp tồn tại một hàm ảo và không thể dùng lớp này để định nghĩa một đối
tượng.
Xét chương trình sau:

#include <iostream.h>
#include <conio.h>

class format
{
public;
void display_form();
virtual void header()
{
cout << this is a header\n”;
}
virtual void body() = 0; // hàm thuần ảo
virtual void footer()
{
cout << “this is a footer\n\n”;
}
}
void Format :: display_form()
{
header();
for( int index = 0;index <3 ; index ++)
{
body();
}
footer();

class MyForm : public Format


{
public:
void body() { cout << “This is the new body of text\n”;}
void footer(){ cout << This is the new footer\n”;}

};
void main()
{
clrscr();
Format* first_form = new MyForm;
First_form->display_form();
}

Trang 40
Lập trình hướng đối tượng với C++

6.4 Hàm hủy ảo(Virtual destructors).


Hàm hủy là hàm được gọi một cách tự động để thực hiện một số công việc nào đó mà
người lập trình cần khi đối tượng bị hủy , chẳng hạn hàm hủy dùng để giải phóng bộ nhớ một cách
tự động khi đối tượng bị hủy. Tuy nhiên bình thường thì hàm hủy của lớp dẫn xuất sẽ không được
gọi mà chỉ có hàm hủy của lớp cơ bản được gọi , nên trong một số trường hợp ta không thể dùng
hàm ảo trong một lớp dẫn xuất để thực hiện các thao tác mà ta cần khi một làm khi một đối tượng
của lớp mày bị hủy. Vấn đền này được giải quyết bằng cách dúng hàm hủy ảo. Hàm hủy của lớp
cơ bản sẽ là một hàm ảo, các lớp dẫn xuất sẽ có hàm hủy riêng và khi đối tượng bị hủy ,hàm hủy
của lớp cơ bản và lớp dẫn xuất đều sẽ được gọi.
Xột vớ dụ sau;
#include <iostream.h>
class Base
{
public:
~Base()
{
cout<<"~Base"<<endl;
}
};
class Derived:public Base
{
public:
~Derived()
{
cout<<"~Derived"<<endl;
}
};
int main()
{
Base *B;
B = new Derived;
delete B;
return 0;
}
Kết quả khi thực hiện :

~Base
Như vậy ta thấy chỉ có hàm hủy của lớp cơ bản được gọi , cũn hàm hủy của lớp dẫn xuất không
được gọi .

Bây giờ ta sửa lại chương trình trên như sau:

#include <iostream.h>
class Base
{
public:
virtual ~Base()
{
cout<<"~Base"<<endl;
}

Trang 41
Lập trình hướng đối tượng với C++

};
class Derived:public Base
{
public:
virtual ~Derived()
{
cout<<"~Derived"<<endl;
}
};
int main()
{
Base *B;
B = new Derived;
delete B;
return 0;
}

Khi đó kết quả của chương trình sẽ là ;


~ Base
~Derived
Bài tập làm thêm
Xây dựng các lớp theo sơ đồ sau đây :

HINH

H_TRON H_CHUNHAT

Trong đó HINH là lớp cơ bản, H_TRON, H_CHUNHAT là các lớp dẩn xuất, lớp hình có
các hàm ảo thuần ảo
virtual void Ve() // hàm vẽ hình ra màn hình
virtual int TinhDienTich() // hàm tớnh diện tớch
Các lớp dẫn xuất sẽ viết lại các hàm trên để vẽ hay tính diện tích cho thích hợp.

Trang 42

You might also like