1. Trang chủ
  2. » Công Nghệ Thông Tin

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

51 591 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Lớp, đối tượng và tính đóng gói
Trường học Trường Đại Học
Chuyên ngành Công Nghệ Thông Tin
Thể loại bài giảng
Định dạng
Số trang 51
Dung lượng 92,31 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Bài giảng lập trình hướng đối tượng - Thầy Cường Học viện bưu chính viễn thông TP HCM

Trang 1

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

Trang 3

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á Ý nghiã

class khai báo một lớp

private : 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

public : 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)

Trang 4

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"

myclass ob1, ob2; // khai báo 2 đối tượng có tên ob1, ob2

ob1.set_a(10); // thiết lập giá trị 10 cho bản sao cuả biến a của ob1

ob2.set_a(99); // 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;

}

Trang 5

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; // ERROR! cannot access private member

ob2.a = 99; // by non-member functions

myclass ob1, ob2;

// here, a is accessed directly

Trang 6

Ví dụ 1.4 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

cout << "Stack is empty";

return 0; // return null on empty stack

Trang 7

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 đó

Trang 8

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 ;

class_name() ; // khai báo hàm tạo

} objects_list ;

Ví dụ 2.1 Lớp myclass có hàm tạo myclass() và hàm show()

#include <iostream.h>

Trang 9

Đố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

Trang 10

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(); // khai báo hàm hủy

Trang 11

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 Dùng hàm tạo stack() để tự động khởi đầu ngăn xếp khi đối tượng được tạo

#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

Trang 12

cout << "Stack is empty\n";

return 0; // return null on empty stack

Trang 13

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

Trang 15

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

Trang 16

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)

- 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 :

Trang 17

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ố

Ví dụ 3.1 Hàm tạo myclass(int x) có một tham số

Trang 18

• 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 tạo

Trang 19

#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

Trang 20

cout << "Stack " << who << " is empty\n";

return 0; // return null on empty stack

// 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";

Trang 22

// use variables to construct ob

myclass ob(x, y);

ob.show();

return 0;}

Trang 23

Bài tập III

1 Viết chương trình thay đổi lớp stack để cho nó cấp phát bộ nhớ động cho ngăn xếp chứa các ký tự Kích thước ngăn xếp được chỉ rõ bằng một tham số với hàm tạo Hàm hủy giải phóng bộ nhớ động

2 Hãy tạo lớp t_and_d để truyền ngày và giờ hệ thống hiện hành như một tham số

cho hàm tạo của nó khi được tạo ra Lớp gồm có hàm thành viên hiển thị ngày giờ này lên màn hình Dùng các hàm ngày và giờ chuẩn trong thư viện chuẩn để tìm và hiện thị ngày

3 Viết chương trình tạo lớp box có hàm tạo được truyền 3 giá trị double, diễn tả độ dài các cạnh của hộp Hãy cho lớp box tính thể tích của hình lập phương và lưu trữ kết qủa trong biến double Tạo hàm thành viên vol() để hiển thị thể tích của mỗi đối tượng box

IV/ Nội tuyến tự động (in-line)

1/ Khái niệm

Khi định nghiã hàm thành phần là đủ ngắn thì có thể đặt định nghiã trong khai báo

hàm trong lớp đó Hàm này sẽ được gọi là hàm nội tuyến (in-line func.) và không

cần dùng từ khoá inline đứng trước hàm đó

// divisible() is defined here and automatically in-lined

int divisible() { return !(i%j) ; }

};

Trang 24

samp(int a, int b) { i = a; j = b; } // inline constructor

int divisible() { return !(i%j); }

};

Ví dụ 4.3 Một hàm ngắn ở bên trong một khai báo lớp

cho dù đặc điểm nội tuyến tự động là không có giá trị

class myclass {

int i;

public:

myclass(int n) { i = n; }

Trang 25

void show() { cout << i; }

Một đối tượng được gán cho một đối tượng khác để cả hai đối tượng có cùng kiểu,

khi đó sự sao chép từng bit của các thành viên dữ liệu được thực hiện

void set(int i, int j) { a = i; b = j; }

void show() { cout << a << ' ' << b << "\n"; }

Trang 26

void set(int i, int j) { a = i; b = j; }

void show() { cout << a << ' ' << b << "\n"; }

void set(int i, int j) { a = i; b = j; }

void show() { cout << a << ' ' << b << "\n"; }

};

Trang 27

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

Trang 28

cout << "Stack is empty\n";

return 0; // return null on empty stack

s2 = s1; // now s1 and s2 are identical

for(i=0; i<3; i++) cout << "Pop s1: " << s1.pop() << "\n";

for(i=0; i<3; i++) cout << "Pop s2: " << s2.pop() << "\n";

Trang 29

return 0;

}

c/ Đối với các đối tượng có sử dụng chuổi, khi thực hiện phép gán đối tượng phải

chắc chắn rằng không hủy bỏ các thông tin cần thiết trong đối tượng đó

Trang 31

VI/ Truyền các đối tượng sang hàm

1/ Việc truyền các đối tượng cho hàm giống như truyền các đối số thông thường

Tham số của hàm có kiểu dữ liệu là kiểu lớp, và đối số truyền cho hàm chính là đối tượng

Giống như các kiểu dữ liệu khác, theo ngầm định, tất cả các đối tượng được truyền bởi giá trị cho một hàm

Ví dụ 6.1 Truyền một đối tượng cho hàm

#include <iostream.h>

class samp {

int i;

public:

Trang 33

however

void sqr_it(samp o)

{

o.set_i( o.get_i() * o.get_i() ) ;

cout << "Copy of a has i value of " << o.get_i();

sqr_it(a) ; // a passed by value, displays 100

cout << "But, a.i is unchanged in main: ";

cout << a.get_i(); // displays 10

/* Set o.i to its square This affects the calling argument */

void sqr_it(samp *o)

{

Trang 34

sqr_it(&a); // pass a's address to sqr_it(), displays 100

cout << "Now, a in main() has been changed: ";

cout << a.get_i(); // displays 100

return 0;

}

4/ Bản sao của đối tượng

Khi truyền một đối tượng cho hàm, một bản sao của đối tượng được thực hiện, có nghĩa là một đối tượng mới xuất hiện Do đó khi hàm kết thúc làm việc, bản sao của đối tượng đó (đối số của hàm) sẽ bị hủy

Điều này làm nảy sinh hai vấn đề :

- Hàm tạo của đối tượng được gọi khi bản sao thực hiện ?

- Hàm hủy của đối tượng được gọi khi bản sao bị hủy ?

Khi bản sao của một đối tượng được thực hiện để dùng gọi hàm, thì hàm tạo không được gọi Do hàm tạo thường được dùng để khởi đầu một khiá cạnh nào đó của đối

tượng Khi truyền một đối tượng cho một hàm, bạn cần đến trạng thái hiện hành của đối tượng chứ không phải trạng thái ban đầu

Khi hàm kết thúc và bản sao bị hủy, hàm hủy được gọi

Ví dụ 6.4

#include <iostream.h>

class samp {

int i;

Trang 35

~samp() { cout << "Destructing\n"; }

int get_i() { return i; }

Hàm hủy của bản sao đối tượng được gọi khi hàm kết thúc có thể là nguyên nhân của

nhiều vấn đề

Chẳng hạn, nếu đối tượng có hàm tạo cấp phát bộ nhớ động hoặc hàm hủy giải phóng bộ nhớ động, thì bản sao của đối tượng sẽ giải phóng bộ nhớ động khi hàm

Trang 36

hủy của nó được gọi Điều này làm cho đối tượng gốc bị hỏng và trở thành vô dụng

~dyna() { free(p); cout << "freeing \n"; }

int get() { return *p; }

// Return negative value of *ob.p

int neg(dyna ob)

Trang 37

cout << neg(o) << "\n"; // freeing

// 10 dyna o2(20);

cout << o2.get() << "\n"; // 20

cout << neg(o2) << "\n"; // freeing

// -20 cout << o.get() << "\n"; // 20 do *p được cấp địa chỉ vùng nhớ động

cout << neg(o) << "\n"; // freeing

// -20 return 0; // freeing o

// Null pointer assignment

}

Giải thích nguyên nhân gây lổi ?

• Có thể khắc phục bằng cách truyền điạ chỉ của đối tượng cho hàm Vì sẽ không có đối tượng mới được tạo ra và không có hàm hủy của bản sao đối tượng được gọi khi hàm trả về

Tuy nhiên, giải pháp tốt nhất là sử dụng hàm tạo bản sao (copy constructor), cho

phép định nghiã cách thức tạo các bản sao của các đối tượng (xem chương sau)

Bài tập VI

1 Viết chương trình tạo lớp stack trong ví dụ 5.3 chương 2, bổ sung hàm showstack() để truyền một đối tượng kiểu stack Cho hàm này hiển thị nội dung của ngăn xếp

2 Tìm lỗi sai trong chương trình này

Trang 38

dyna(int i);

~dyna() { free(p); cout << "freeing \n"; }

int get() { return *p; }

// Return negative value of *ob.p

int neg(dyna ob)

Trang 39

}

VII/ Trả đối tượng từ hàm

Đối tượng trả về từ hàm thông qua câu lệnh return Khi đó một đối tượng tạm

được tự động tạo ra để giữ giá trị trả về

Chính đối tượng này thực sự được trả về bởi hàm Sau khi giá trị được trả về, đối tượng này bị hủy, sự hủy đối tượng tạm có thể gây ra tác dụng ngoài ý muốn

void show() { cout << s << "\n"; }

void set(char *str) { strcpy(s, str); }

Trang 40

int main()

{

samp ob;

// assign returned object to ob

ob = input(); // Enter a string: Hello ↵

~samp() { if(s) free(s); cout << "Freeing s\n"; }

void show() { cout << s << "\n"; }

Trang 41

// Return an object of type samp

// assign returned object to ob

ob = input(); // This causes an error!!!!

ob.show();

return 0;

}

Hãy giải thích kết quả của chương trình ?

Enter a astring: Hello

Hello

Null pointer assignment

Khi một đối tượng được trả về từ một hàm, một đối tượng tạm được dùng để thực

hiện sự trả về sẽ làm hủy bộ nhớ (được cấp phát cho chuổi s) của đối tượng được gọi Để tránh tình trạng này có thể sử dụng hàm tạo bản sao

Trang 42

Bài tập VII

1 Viết chương trình tạo lớp Who, cho hàm tạo của Who nhận một đối số ký tự mà đối số này được dùng để nhận dạng một đối tượng

Hãy cho hàm tạo hiển thị một thông báo tương tự thông báo sau đây khi tạo ra một đối tượng :

Constructing who #x Trong đó x là ký tự nhận dạng

Hãy tạo hàm make_who() để trả về đối tượng Who Hãy cho mỗi đối tượng một tên duy nhất

VIII/ Các hàm friend

Một hàm friend không phải là hàm thành viên của lớp nhưng có thể truy cập các thành viên riêng của lớp

Một hàm friend được định nghiã như một hàm bình thường Nếu nằm bên trong một lớp, hàm friend sẽ có từ khoá friend đứng trước

Hàm friend không được kế thừa từ lớp dẫn xuất (xem chương 6)

• Các lợi ích khi dùng hàm friend :

+ sự quá tải toán tử (xem chương 5)

+ tạo ra các kiểu hàm nhập/xuất nào đó (xem chương 8)

+ tạo hàm để truy cập các thành viên riêng của hai hay nhiều lớp khác nhau

Ngày đăng: 21/08/2012, 15:34

TỪ KHÓA LIÊN QUAN

TRÍCH ĐOẠN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w