Tải bản đầy đủ (.pdf) (51 trang)

LẬP TRÌNH ĐỐI TƯỢNG CHƯƠNG 2

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (92.31 KB, 51 trang )

Chương 2

Lớp, đối tượng và tính đóng gói

• Lớp
• Hàm tạo, hàm hủy
• Tham số của hàm tạo
• Nội tuyến tự động
• Gán đối tượng
• Truyền các đối tượng sang hàm
• Trả đối tượng từ hàm
• Hàm friend


Chương 2

Lớp, Đối tượng và tính đóng gói

17

17


Chương 2

Lớp, Đối tượng và tính đóng gói

I/ Lớp (class)
• Cú pháp khai báo lớp
class class_name {
private :


// khai báo các biến ;
// khai báo các hàm;
public :
// khai báo các biến ;
// khai báo các hàm;
} objects_list ;
class_name tên của lớp do người dùng định nghiã.
objects_list danh sách các đối tượng, có thể tùy chọn.
Các biến, các hàm khai báo bên trong một lớp gọi là các thành viên của lớp đó.
Từ khoá
class
private :
public :

Ý nghiã
khai báo một lớp
qui định các biến, các hàm là các thành viên riêng của lớp, bên
ngoài lớp không thể truy cập được.
qui định các biến, các hàm là các thành viên chung của lớp, có
thể truy cập chúng từ các thành viên khác của lớp và bởi các
thành phần khác của chương trình có chứa lớp đó.

• Cú pháp định nghiã hàm thành viên
data_type class_name :: func_name (arg_list)
{
// body of function
}

data_type kiểu dữ liệu của phương thức trả về
class_name tên lớp chứa hàm

toán tử phân giải phạm vi (scope resolution operator)
::
18

18


Chương 2

Lớp, Đối tượng và tính đóng gói

19

func_name tên hàm
arg_list
danh sách các đối số

Ví dụ 1.1

Khai báo lớp có tên "myclass"

class myclass {
// private to myclass
int a;
public:
void set_a(int num);
int get_a();
};
void myclass::set_a(int num)
{

a = num;
}
int myclass::get_a()
{
return a;
}
int main()
{
myclass ob1, ob2;
ob1.set_a(10);
ob2.set_a(99);

// định nghiã hàm void set_a(int num)

// định nghiã hàm int get_a()

// khai báo 2 đối tượng có tên ob1, ob2
// thiết lập giá trị 10 cho bản sao cuả biến a của ob1
// thiết lập giá trị 99 cho bản sao cuả biến a của ob2

cout << ob1.get_a() << "\n";
cout << ob2.get_a() << "\n";
return 0;
}

19


Chương 2


Lớp, Đối tượng và tính đóng gói

Ví dụ 1.2

Lỗi biên dịch khi truy cập đến biến riêng a từ bên ngoài lớp myclass

int main()
{
myclass ob1, ob2;

}

ob1.a = 10;
ob2.a = 99;
return 0;

// ERROR! cannot access private member
//
by non-member functions.

Khi a là biến chung, có thể truy cập a từ bên ngoài lớp myclass
Ví dụ 1.3
#include <iostream.h>
class myclass {
public:
// now a is public
int a;
// and there is no need for set_a() or get_a()
};
int main()

{
myclass ob1, ob2;
// here, a is accessed directly
ob1.a = 10;
ob2.a = 99;
cout << ob1.a << "\n";
cout << ob2.a << "\n";
return 0;
}

20

20


Chương 2

Ví dụ 1.4

Lớp, Đối tượng và tính đóng gói

21

Tạo lớp stack dùng để chứa các ký tự

#include <iostream.h>
#define SIZE 10
// Declare a stack class for characters
class stack {
char stck[SIZE]; // holds the stack

int tos;
// index of top-of-stack
public:
void init();
// initialize stack
void push(char ch);
// push character on stack
char pop();
// pop character from stack
};
// Initialize the stack
void stack::init()
{
tos = 0;
}
// Push a character.
void stack::push(char ch)
{
if(tos == SIZE) {
cout << "Stack is full";
return;
}
stck[tos] = ch;
tos++;
}
// Pop a character.
char stack::pop()
{
if(tos == 0) {
cout << "Stack is empty";

return 0; // return null on empty stack
21


Chương 2

Lớp, Đối tượng và tính đóng gói

22

}
tos--;
return stck[tos];
}
int main()
{
stack s1, s2; // create two stacks
int i;
// initialize the stacks
s1.init();
s2.init();
s1.push('a');
s2.push('x');
s1.push('b');
s2.push('y');
s1.push('c');
s2.push('z');
for(i=0; i<3; i++) cout << "Pop s1: " << s1.pop() << "\n";
for(i=0; i<3; i++) cout << "Pop s2: " << s2.pop() << "\n";
return 0;

}

@ Kết quả xuất dữ liệu của chương trình ?

• Lưu ý
Khai báo lớp là một trừu tượng logic để định nghiã một kiểu dữ liệu mới.
Khai báo một đối tượng dựa vào lớp, tạo ra một thực thể vật lý (có điạ chỉ trong bộ
nhớ) có kiểu dữ liệu đó.

22


Chương 2

Lớp, Đối tượng và tính đóng gói

23

Mỗi đối tượng của một lớp có bản sao riêng của các biến được khai báo trong lớp.

Bài tập I
1. Hãy tạo lớp card để giữ các mục nhập catalog thẻ thư viện, chưá tựa đề sách (kiểu
chuỗi), tên tác giả (kiểu chuỗi) và số bản (kiểu nguyên). Dùng hàm thành viên
chung store() để lưu trữ thông tin về sách và hàm thành viên chung show() để hiển
thị thông tin. Viết chương trình thực hiện yêu cầu trên.
2. Tạo lớp hàng đợi (queue) để giữ hàng các số nguyên. Tạo một kích thước hàng
dài 100 số nguyên. Viết chương trình thực hiện yêu cầu trên.

II/ Hàm tạo & hàm hủy
1/ Khái niệm

Hàm tạo (constructor) có cùng tên với lớp, là hàm thành phần của một lớp,
không có kiểu trả về.
Mục đích của hàm tạo nhằm tạo ra các khởi đầu cho một đối tượng.
Hàm tạo được gọi tự động mỗi khi đối tượng của lớp đó được tạo ra.
2/ Khai báo
class class_name {
// khai báo các biến và hàm ;
public :
// khai báo các biến và hàm ;
// khai báo hàm tạo
class_name() ;
} objects_list ;

Lớp myclass có hàm tạo myclass() và hàm show()
Ví duï 2.1
#include <iostream.h>
23


Chương 2

Lớp, Đối tượng và tính đóng gói

class myclass {
int a;
public:
myclass() ;
void show();
};


24

// constructor

myclass::myclass() // định nghiã hàm tạo
{
cout << "In constructor\n";
a = 10;
}
void myclass::show()
{
cout << a;
}
int main()
{
myclass ob;
ob.show();
return 0;
}

// hàm tạo myclass() được gọi tự động khi đối tượng ob được tạo ra

Đối với các đối tượng chung, một hàm tạo của đối tượng được gọi một lần khi
chương trình bắt đầu thi hành lần đầu.
Đối với các đối tượng riêng, hàm tạo của đối tượng được gọi mỗi khi lệnh khai báo
được thi hành.
3/ Khái niệm hàm hủy (destructor)
Hàm hủy có cùng tên với lớp, có kèm theo dấu ~ đứng trước, là hàm thành phần của
một lớp, không có kiểu trả về.
Mục đích của hàm hủy nhằm thi hành một số tác động khi đối tượng bị hủy bỏ,

chẳng hạn một đối tượng yêu cầu cấp phát bộ nhớ khi đối tượng được tạo ra và giải
24


Chương 2

Lớp, Đối tượng và tính đóng gói

25

phóng bộ nhớ khi đối tượng bị hủy bỏ.
Hàm hủy được gọi tự động mỗi khi đối tượng của lớp đó bị hủy bỏ.
4/ Khai báo
class class_name {
// khai báo các biến và hàm ;
public :
// khai báo các biến và hàm ;
class_name();
~class_name();
} objects_list ;

// khai báo hàm tạo
// khai báo hàm hủy

Lớp myclass có hàm tạo myclass() và hàm hủy ~myclass()
Ví dụ 2.2
#include <iostream.h>
class myclass {
int a;
public:

myclass();
~myclass();
void show();
};

// constructor
// destructor

myclass::myclass()
{
cout << "In constructor\n";
a = 10;
}
myclass::~myclass()
{
cout << "Destructing...\n";
}

25


Chương 2

Lớp, Đối tượng và tính đóng gói

26

void myclass::show()
{
cout << a << "\n";

}
int main()
{
myclass ob;
ob.show();
return 0;
}

Đối với các đối tượng chung, hàm hủy của đối tượng được gọi khi chương trình kết
thúc.
Đối với các đối tượng riêng, hàm hủy của đối tượng được gọi khi chúng ra khỏi phạm
vi.
• Lưu ý : Không thể biết được địa chỉ của hàm tạo hoặc hàm hủy.
Ví dụ 2.3
tạo

Dùng hàm tạo stack() để tự động khởi đầu ngăn xếp khi đối tượng được

#include <iostream.h>
#define SIZE 10
// Declare a stack class for characters.
class stack {
char stck[SIZE]; // holds the stack
int tos;
// index of top-of-stack
public:
stack();
// constructor
void push(char ch);
// push character on stack

char pop();
// pop character from stack
};
// Initialize the stack.
26


Chương 2

Lớp, Đối tượng và tính đóng gói

27

stack::stack()
{
cout << "Constructing a stack\n";
tos = 0;
}
// Push a character.
void stack::push(char ch)
{
if(tos==SIZE) {
cout << "Stack is full\n";
return;
}
stck[tos] = ch;
tos++;
}
// Pop a character.
char stack::pop()

{
if(tos==0) {
cout << "Stack is empty\n";
return 0;
// return null on empty stack
}
tos--;
return stck[tos];
}
int main()
{
// Create two stacks that are automatically initialized.
stack s1, s2;
int i;
s1.push('a');
s2.push('x');
s1.push('b');
27


Chương 2

Lớp, Đối tượng và tính đóng gói

s2.push('y');
s1.push('c');
s2.push('z');
for(i=0; i<3; i++) cout << "Pop s1: " << s1.pop() << "\n";
for(i=0; i<3; i++) cout << "Pop s2: " << s2.pop() << "\n";
return 0;

}

Ví dụ 2.4

Dùng hàm tạo strtype() và hàm hủy ~strtype() để tự động cấp phát
bộ nhớ cho chuổi *p và giải phóng bộ nhớ khi đối tượng bị hủy.

#include <iostream.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#define SIZE 255
class strtype {
char *p;
int len;
public:
strtype(); // constructor
~strtype(); //destructor
void set(char *ptr);
void show();
};
// Initialize a string object.
strtype::strtype()
{
p = (char *) malloc(SIZE);
if(!p) {
cout << "Allocation error\n";
28

28



Chương 2

Lớp, Đối tượng và tính đóng gói

29

exit(1);

}

}
*p = '\0';
len = 0;

// Free memory when destroying string object.
strtype::~strtype()
{
cout << "Freeing p\n";
free(p);
}
void strtype::set(char *ptr)
{
if(strlen(ptr) >= SIZE) {
cout << "String too big\n";
return;
}
strcpy(p, ptr);
len = strlen(p);

}
void strtype::show()
{
cout << p << " - length: " << len;
cout << "\n";
}
int main()
{
strtype s1, s2;
s1.set("This is a test.");
s2.set("I like C++.");
s1.show();
29


Chương 2

Lớp, Đối tượng và tính đóng gói

s2.show();
return 0;
}

Ví dụ 2.5

Dùng đối tượng của lớp timer để xác định khoảng thời gian
khi một đối tượng kiểu timer được tạo và cho đến khi bị hủy.

#include <iostream.h>
#include <ctime.h>

class timer {
clock_t start;
public:
timer(); // constructor
~timer(); // destructor
};
timer::timer()
{
start = clock();
}
timer::~timer()
{
clock_t end;
end = clock();
cout << "Elapsed time: " << (end-start) / CLOCKS_PER_SEC << "\n";
}
int main()
{
timer ob;
char c;

30

30


Chương 2

Lớp, Đối tượng và tính đóng gói


31

// delay ...
cout << "Press a key followed by ENTER: ";
cin >> c;
return 0;
}
Chương trình này dùng hàm thư viện chuẩn clock() để trả về số chu kỳ đồng hồ xảy
ra từ khi chương trình bắt đầu chạy. Chia giá trị này cho hằng số CLK-TCK để
chuyển thành giá trị giây. (CLK-TCK định nghiã số tic-tắc của đồng hồ trong một
giây)

Bài tập II
1. Thực hiện lại lớp queue trong bài tập I/ 2. chương 2 để thay hàm khởi đầu bằng
hàm tạo.
2. Tạo lớp stopwatch để so với đồng hồ bấm giờ trong việc xác định thời gian trôi
qua, được tính bằng giây. Các yêu cầu :
- Lớp stopwatch có 2 biến riêng start và end lưu số giây
- Viết hàm tạo để đạt thời gian trôi qua lúc đầu về zero.
- Hai hàm thành viên start() và stop() để lần lượt mở và tắt chế độ định giờ.
- Hàm thành viên show() để hiển thị thời gian trôi qua.
- Viết hàm hủy để tự động hiển thị thời gian trôi qua khi đối tượng stopwatch bị hủy.
3. Sửa lỗi trong đoạn chương trình sau :
class sample {
double a, b, c;
public :
double sample() ;
}

III/ Tham số của hàm tạo

31


Chương 2

Lớp, Đối tượng và tính đóng gói

32

1/ Khái niệm
Hàm tạo có thể có các tham số, chỉ cần bổ sung các tham số thích hợp trong khai báo
lớp và trong định nghóa hàm tạo.
Khi khai báo một đối tượng, cần chỉ rõ các tham số này làm đối số.
Hàm tạo myclass(int x) có một tham số
Ví dụ 3.1
#include <iostream.h>
class myclass {
int a;
public:
myclass(int x);
// constructor
void show();
};
myclass::myclass(int x)
{
cout << "In constructor\n";
a = x;
}
void myclass::show()
{

cout << a << "\n";
}
int main()
{
myclass ob(4);
ob.show();
return 0;
}
Giaù trị 4 trong khai báo đối tượng ob(4), là đối số được truyền cho tham số x của
hàm tạo myclass(int x), dùng để khởi tạo biến a.
Cách viết khác (dài hôn)
myclass ob = myclass (4) ;
32


Chương 2

Lớp, Đối tượng và tính đóng gói

33

• Lưu ý hàm hủy không có tham số. Do không có cơ chế nào để truyền đối số cho
một đối tượng bị hủy.

Ví dụ 3.2

Có thể truyền nhiều tham số cho hàm taïo

#include <iostream.h>
class myclass {

int a, b;
public:
myclass(int x, int y);
void show();
};

// constructor

myclass::myclass(int x, int y)
{
cout << "In constructor\n";
a = x;
b = y;
}
void myclass::show()
{
cout << a << ' ' << b << "\n";
}
int main()
{
myclass ob(4, 7);
ob.show();
return 0;
}

Ví dụ 3.3

Dùng hàm tạo được tham số hóa để truyền "tên" cho stack.
33



Chương 2

Lớp, Đối tượng và tính đóng gói

#include <iostream.h>
#define SIZE 10
// Declare a stack class for characters.
class stack {
char stck[SIZE];
// holds the stack
int tos;
// index of top-of-stack
char who;
// identifies stack
public:
stack(char c);
// constructor
void push(char ch);
// push character on stack
char pop();
// pop character from stack
};
// Initialize the stack.
stack::stack(char c)
{
tos = 0;
who = c;
cout << "Constructing stack " << who << "\n";
}

// Push a character.
void stack::push(char ch)
{
if(tos == SIZE) {
cout << "Stack " << who << " is full\n";
return;
}
stck[tos] = ch;
tos++;
}
// Pop a character.
char stack::pop()
{
if(tos == 0) {
34

34


Chương 2

Lớp, Đối tượng và tính đóng gói

35

cout << "Stack " << who << " is empty\n";
return 0; // return null on empty stack

}
tos--;

return stck[tos];
}

int main()
{
// Create two stacks that are automatically initialized.
stack s1('A'), s2('B');
int i;
s1.push('a');
s2.push('x');
s1.push('b');
s2.push('y');
s1.push('c');
s2.push('z');

}

// This will generate some error messages.
for(i=0; i<5; i++) cout << "Pop s1: " << s1.pop() << "\n";
for(i=0; i<5; i++) cout << "Pop s2: " << s2.pop() << "\n";
return 0;

@ Mục đích : dùng để nhận ra tên stack nào được tham chiếu khi có lỗi xảy ra.
Điều này rất có ích trong quá trình gỡ rối (debug).

Ví dụ 3.4

Đối số của hàm tạo là một chuổi.

#include <iostream.h>

#include <string.h>
#include <stdlib.h>
#include <malloc.h>
35



×