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

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

174 977 4
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 Trình Hướng Đối Tượng
Trường học Trường Đại Học Công Nghệ Thông Tin
Chuyên ngành Lập Trình
Thể loại Đồ Án
Thành phố Thành Phố Hồ Chí Minh
Định dạng
Số trang 174
Dung lượng 615 KB

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

Nội dung

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

Trang 1

Mục lục

Mục lục 1

lời nói đầu 5

chơng 1: Mở đầu 6

Bài 1 So sánh giữa lập trình hớng đối tợng và lập trình hớng thủ tục 6

1 Lập trình hớng thủ tục 6

2 Lập trình hớng đối tợng 7

Bài 2 Giới thiệu ngôn ngữ C++ 9

1 Chú thích trong C và trong C++ 9

2 Các từ khóa mới 9

3 Phép chuyển kiểu bắt buộc 10

4 Khai báo biến 10

5 Hàm main 11

6 Truyền tham số cho hàm 11

7 Nhắc lại về biến con trỏ 15

8 Sử dụng tham số truyền ngầm định trong hàm .17 9 Cấp phát và giải phóng bộ nhớ 19

10 Các hàm tải bội (Overloaded function) 20

11 Hàm inline 22

12 Khả năng vào ra mới của C++ 26

Bài 3 Một số khái niệm cơ bản của lập trình h-ớng đối tợng 30

1 Khái niệm đối tợng (Object) 30

2 Lớp đối tợng (Class) 30

3 Trừu tợng hoá dữ liệu và bao gói thông tin (Abstraction and Encapsulation) 30

4 Sự kế thừa (Inheritance) 31

Trang 2

chơng 2: Lớp các đối tợng 37

Bài 1 lớp các đối tợng 37

1 Khai báo lớp các đối tợng 37

2 Các thành phần trong lớp (Data member and function member) 41

3 Đối tợng trong tham số của hàm 52

Bài 2 Constructor và destructor 56

Bài 3 Toán tử tải bội và toán tử tải bội thân thiện 60

1 Khái quát chung 60

2 Toán tử tải bội 60

3 Bài tập 1 65

4 Toán tử tải bội thân thiện 66

5 Bài tập 2 75

6 Chuyển đổi kiểu 76

Bài 4 Vài vấn đề về sử dụng từ khoá const 84 1 Sử dụng biến kiểu const 84

2 Truyền tham số kiểu const cho hàm 85

3 Đối tợng hằng của lớp 87

4 Hàm thành phần const (hàm thành phần có khai báo const phía sau) 89

5 Con trỏ this kiểu const (hàm thành phần có khai báo const phía trớc) 92

6 Lớp các dãy bit 94

7 Nghiên cứu lớp lớp String 98

chơng 3: Sự kế thừa - inheritance 105

Bài 1 Sự tơng ứng trong kế thừa 105

1 Khái niệm chung 105

Trang 3

2 Kế thừa đơn 106

3 Thành phần protected trong kế thừa 108

4 Kế thừa đa mức 113

5 Kế thừa phân cấp 114

6 Kế thừa bội 114

7 Kế thừa kép (lai ghép) 116

8 Constructor trong các lớp kế thừa 120

Bài 2 Con trỏ xác định thành phần của lớp và con trỏ xác định đối tợng 124

1 Các ký hiệu cú pháp về con trỏ 124

2 Các ví dụ 125

3 Con trỏ xác định đối tợng 127

Bài 3 Hàm ảo và tơng ứng bội trong kế thừa .132

1 Các hàm dịch chuyển (Override function) 132

2 Con trỏ xác định đối tợng trong quan hệ kế thừa 133

3 Con trỏ hàm ảo và tơng ứng bội 135

4 Kế thừa lai ghép và lớp cơ sở ảo 138

5 Hàm rỗng (Null Function) 141

6 Hàm ảo thực sự và lớp trừu tợng (pure function & abstract class) 142

7 Hàm thân thiện ảo và toán tử ảo dịch chuyển 144

chơng 4: lớp mẫu và hàm mẫu 145

Khái quát 145

1 Hàm mẫu 145

2 Lớp mẫu 148

Phụ lục - Giới thiệu Một số bài toán phân tích thiết kế hớng đối tợng trên C++ 154

Trang 4

1 Sơ lợc 5 bớc thực hiện 154

2 Xây dựng lớp hình học phẳng 155

3 Quản lý các lô đất 165

Tài liệu tham khảo 174

Trang 5

lời nói đầu

Trong những năm 1980, ngôn ngữ C đã khẳng định

đợc vị trí quan trọng trong các ngôn ngữ lập trình có cấu trúc bởi tính đa năng của mình Tuy nhiên khi độ phức tạp của bài toán khá lớn thì C không còn đáp ứng đợc đối với các dự án lớn Cần phải thiết kế những phần mềm mang những đợc những đặc tính của thế giới thực bên bên ngoài

Kỹ thuật lập trình xuất phát trên ý tởng này mang tên là là

kỹ thuật lập trình hớng đối tợng (Object Oriented Programing viết tắt là OOP) và trên kỹ thuật này nhiều trình biên dịch đã đợc thiết kế nh Smalltalk, C++

Lập trình hớng đối tợng đợc phát triển từ ngôn ngữ lập trình có cấu trúc nhng thay vì xoay quanh chức năng của nhiệm vụ đã đặt ra, lập trình hớng đối tợng lại đặt trọng tâm vào việc xử lý các dữ liệu để thực hiện các chức năng đó Trong lập trình hớng đối tợng, khái niệm về đối t-ợng (Object) trở thành một khái niệm trọng tâm và hầu nhmọi công việc trong một chơng trình đều đợc tiến hành trên các đối tợng này

Những vấn đề trọng tâm và mới mẻ của lập trình ớng đối tợng với C++ mà chúng ta cần phải tập trung nghiên cứu là:

h-• Sự bao gói (Encapsulation)

• Sự kế thừa (Inheritance)

• Sự tơng ứng bội (Polymorphism)

Trang 6

h-* Vậy trọng tâm của lập trình hớng thủ tục là phân rã bài toán thành các hàm chức năng theo kỹ thuật top-down Bài toán đợc giải quyết bởi một số hàm chính Các hàm chính lại có thể phân chia thành các bài toán con - tức

là các hàm chức năng nhỏ hơn nữa Một số hàm có thể gọi thực hiện (dùng chung) một số hàm chức năng nhỏ hơn

Nh vậy, cấu trúc các hàm của một chơng trình lập trình ớng thủ tục là cấu trúc phân cấp các hàm:

h-* Việc chú ý tới các hàm trong chơng trình sẽ không quan tâm nhiều đến dữ liệu Dữ liệu của toàn bộ chơng trình đợc các hàm dùng chung và biến đổi từ hàm này sang hàm khác Bản thân trong các hàm cũng có dữ liệu riêng

main

Hàm4

Trang 7

* Vậy đặc trng của lập trình hớng thủ tục là

1 Tập trung vào công việc cần thực hiện - thuật toán

2 Chơng trình đợc chia thành các hàm nhỏ

3 Phần lớn các hàm dùng chung dữ liệu

4 Dữ liệu trong chơng trình chuyển động từ hàm này sang hàm khác

5 Hàm biến đổi dữ liệu từ dạng này sang dạng khác

6 Thiết kế chơng trình theo kỹ thuật top-down

2 Lập trình hớng đối tợng

* Lập trình hớng đối tợng đặt trọng tâm vào đối tợng

và không cho dữ liệu chuyển động trong hệ thống Dữ liệu gắn chặt vào các hàm và thủ tục tạo thành một vùng riêng

và không cho các hàm bên ngoài truy nhập một cách tuỳ tiện

* Lập trình hớng đối tợng phân tích bài toán thành các thực thể gọi là đối tợng, sau đó xây dựng các hàm xung quanh đối tợng đó

* Dữ liệu của đối tợng chỉ có thể truy nhập đợc bởi các hàm của đối tợng Chỉ có một số hàm của đối tợng này

có thể gọi thực hiện các hàm của đối tợng khác biểu thị sự trao đổi thông báo giữa các đối tợng

Đối tượng A Dữ liệu

Trang 8

* Nh vậy đặc trng của lập trình hớng đối tợng là:

1 Tập trung vào dữ liệu thay cho hàm

2 Chia chơng trình thành các đối tợng

3 Dữ liệu đợc thiết kế sao cho đặc tả đợc đối tợng

4 Các hàm đợc xây dựng trên các vùng dữ liệu của

đối tợng và đợc gắn liền với nhau trên cấu trúc dữ liệu đó

5 Dữ liệu đợc bao bọc, che dấu không cho các hàm ngoại lai truy nhập

6 Các đối tợng trao đổi thông báo với nhau thông qua các hàm

7 Dữ liệu và các hàm dễ dàng bổ sung vào đối tợng

8 Chơng trình đợc thiết kế theo kỹ thuật botom up

Trang 9

Bài 2 Giới thiệu ngôn ngữ C++

Trong bài này: với mục đích so sánh ngôn ngữ C và

C++ sẽ làm rõ một số đặc điểm mạnh của C++ so với C,

đồng thời nhấn mạnh thêm hoặc giải thích chi tiết một số vấn đề quan trọng, thờng gặp khi lập trình với C++.

1 Chú thích trong C và trong C++

Trớc hết C++ đợc phát triển từ C nên nó vẫn sử dụng lại tất cả các cú pháp ngôn ngữ nh C và bổ sung thêm một

số cú pháp mới

C++ đa ra một kiểu chú thích mới để tiện chú thích trên một dòng nếu dùng ký pháp // và cũng tiện để viết trên nhiều dòng liên tục nếu dùng cặp ký pháp /* */

Chú thích trong C Chú thích trong C++

/* dong 1 chu thich cua C */

/* dong 2 chu thich cua C */

x=y=0; /*chu thich sau lenh

*/

/* Bat dau chu thich Dong 2 chu thichKet thuc chu thich */

x=y=10; // chu thich sau lenh

publicprivatecdeclpascaldeletetempled

Trang 10

3 Phép chuyển kiểu bắt buộc

Ngoài phép chuyển kiểu nh trong ngôn ngữ C, C++ còn đa ra phép chuyển kiểu mới Xét ví dụ sau đây:

int x=0;

long z=(long)x; // chuyen kieu cua C

long z=long(x); // chuyen kieu cua C++

Nh vậy phép chuyển kiểu trong C++ có dạng nh một hàm số chuyển kiểu đang đợc gọi Cách chuyển kiểu này

rõ ràng vừa khoa học vừa dễ dọc

4 Khai báo biến

Nhìn chung phạm vi hoạt động của biến phụ thuộc vào kiểu của biến và vị trí khai báo của biến trong chơng trình

Ngôn ngữ C đòi hỏi phải khai báo biến trớc phạm

vi mà các biến đang sử dụng Cách khai báo đơn giản nhất trong C là khai báo biến toàn cục lên trớc tất cả các hàm và khai báo biến cục bộ ở đầu thân từng hàm

Trong C++, khác với C, cho phép một cách khai báo biến mới, với cách khai báo này, một biến có thể khai báo

ở vị trí bất kỳ miễn sao là trớc khi sử dụng nó, phạm vi hoạt động của biến trong trờng hợp này là trong khối nơi biến đó đợc khai báo

Ví dụ 1: Khai báo sau đây trong C ++ chấp nhận

nh-ng tronh-ng C là lỗi vì C yêu cầu khai báo biến trớc lệnh

clrscr();

int x;

Ví dụ 2:

void simple()

{ int n; // khai bao cuc bo

for(int i=0; i<10; i++) // cho phep khai bao i trong for { int m;

if (i&1) n+=1

Trang 11

Hàm main trong C không đợc định nghĩa kiểu.

Hàm main trong C++ đợc định nghĩa kiểu để trả lại một giá trị nguyên cho hệ điều hành DOS, do đó phải khai báo là kiểu int, ngầm định-vì vậy sẽ là int Tuy nhiên ta vẫn có thể định nghĩa kiểu void cho hàm main

Khi chơng trình bắt đầu thực hiện, hàm main đợc gọi bởi một chơng trình khởi động đặc biệt (start up code) có sẵn trong C++

Start up code trong C++ có 4 cách gọi (tùy chọn vào Option\ Application):

Dos standard (file C0.ASM)

Dos overlays (file C0.ASM)

Windows Application (file C0w.ASM)

Windows DLL (file C0d.ASM)

Giá trị trả lại của hàm main sẽ đợc Dos sử dụng để kiểm tra lỗi khi thực hiện chơng trình Giá trị này bằng 0 nếu không có lỗi Các giá trị khác 0 đợc C++ biện luận theo các lỗi khi thực hiện chơng trình

6 Truyền tham số cho hàm

C++ vẫn sử dụng 2 cách truyền tham số cho hàm trong C là truyền theo giá trị và truyền theo con trỏ

Tuy nhiên, C++ có thêm một cách mới để truyền tham số cho hàm là truyền tham số kiểu tham chiếu Cách mới này rất hay sử dụng vì thích hợp truyền tham số cho

Trang 12

hàm là địa chỉ của đối tợng - một kiểu dữ liệu mới chỉ có trong C++ (kiểu lớp)

Dới đây ta nhắc lại 2 cách truyền thống và cung cấp cách mới thứ 3

6.1 Truyền tham số kiểu giá trị cho hàm

Theo cách truyền theo giá trị thì chỉ có bản sao của

đối đợc hàm sử dụng Trong thân hàm, các giá trị này có thể bị thay đổi nhng ra khỏi hàm thì giá trị ban đầu của đối vẫn giữ nguyên Đơng nhiên giá trị đầu vào của đối đợc giữ nguyên vì không phải là chính bản thân đối truyền cho hàm

mà là bản sao của đối đợc truyền cho hàm Sự thay đổi các giá trị trong hàm là chỉ thay đổi giá trị của bản sao của nó

void swap(int x,int y)

{int z=x; x=y; y=z;}

6.2 Truyền tham số kiểu con trỏ cho hàm

Khi đối truyền cho hàm kiểu con trỏ thì lúc gọi hàm các con trỏ này sẽ thay thế bằng địa chỉ của các biến để truyền vào hàm hoặc là một con trỏ hoàn toàn xác định nghĩa là đang chứa một địa chỉ của một biến nào đó Nh vậy về bản chất thì bản gốc của đối đợc truyền cho hàm

Kết quả

x = 10 y=5

Trang 13

chứ không phải là bản sao của nó Vì vậy, những giá trị của

đối bị thân hàm làm thay đổi sẽ đợc giữ lại khi hàm kết thúc

- Khi khai báo: void swap(int*,int*)

- Khi định nghĩa: void swap(int *x,int *y) { // dùng

*x và *y; }

- Khi sử dụng: swap(&x,&y)

6.3 Truyền tham số kiểu tham chiếu cho hàm

Tác dụng của việc truyền tham số cho hàm theo tham chiếu cũng giống nh việc truyền tham số cho hàm theo con trỏ Bản chất của hai cách truyền tham số theo con trỏ và theo tham chiếu là truyền cho hàm địa chỉ của

đối chứ không phải là bản sao của đối Vậy các giá trị của

đối bị hàm thay đổi cũng sẽ đợc giữ lại khi ra khỏi hàm

Trang 14

void swap(int &x,int &y)

{int z=x; nx=y; y=z;}

Rõ ràng việc sử dụng tham chiếu đơn giản hơn so với con trỏ Khi truyền theo tham chiếu thì ta chỉ báo hiệu

địa chỉ của đối ở phần khai báo còn lời gọi hàm và nội dung hàm ta vẫn viết tên đối một cách bình thờng

Hai cách truyền theo con trỏ và truyền theo tham chiếu khác nhau ở chỗ: truyền theo tham chiếu tức là làm việc trực tiếp với địa chỉ của đối truyền vào hàm, còn truyền theo con trỏ thì can thiệp gián tiếp vào địa chỉ của

đối, vì con trỏ trong trờng hợp này dùng để chứa địa chỉ của đối và truyền vào hàm

Điều khác biệt này thể hiện rõ hơn với các chú ý sau

Trang 15

7 Nhắc lại về biến con trỏ

7.1 So sánh con trỏ và tham chiếu địa chỉ của biến

Chẳng hạn nếu có khai báo:

int *p; và gán *p=10; thì đơng nhiên có thể viết (*p)++; nhng thậm chí có thể viết p++; Trong khi đó ta không thể có lệnh tăng địa chỉ (&x)++ nếu có khai báo int x;

C++ cho phép viết nh vậy và 2 cách viết có tác dụng khác nhau: Lệnh (*p)++ là tăng 1 đơn vị cho biến nguyên xác định bởi con trỏ p Lệnh p++ là tăng địa chỉ của con trỏ

p, tức là con trỏ p sẽ trỏ vào 2 byte nhớ tiếp theo Vậy lệnh p++ chỉ sử dụng khi dùng p để trỏ vào không phải là 1 số nguyên mà là một dãy các số nguyên chứa trong một dãy các biến động (các bytes nhớ) liên tiếp nhau

Biến con trỏ có 2 cách sử dụng trong chơng trình:

- Sử dụng con trỏ để chứa địa chỉ của biến

- Sử dụng con trỏ để xin cấp phát bộ nhớ động

Ví dụ 1 sau đây nói rằng khi có khai báo biến con trỏ int *p; thì việc sử dụng biến *p giống nh việc sử dụng một biến nguyên nào đó một cách bình thờng

7.2 Sử dụng con trỏ để chứa địa chỉ của biến.

Nếu ta có khai báo

Trang 17

động, con trỏ p phải đợc giữ nguyên có vai trò lu giữ địa chỉ của danh sách Ta gọi là danh sách liên kết để tạo ra một cảm giác các biến động có liên kết với nhau Về mặt bản chất đó là các ô nhớ liên tục đợc cấp phát động, chứ không có liên kết gì cả Lúc chạy chơng trình, phép tăng

địa chỉ q++ làm cho q chỉ vào 2 bytes tiếp theo nghĩa là truy xuất đến biến động tiếp theo tơng ứng

8 Sử dụng tham số truyền ngầm định trong

hàm

C++ còn mạnh hơn C ở chỗ nó cho phép khởi tạo mặc định cho các tham số truyền cho hàm Ta gọi tắt các tham số có khởi tạo giá trị mặc định là các tham số ngầm

Ví dụ 1:

void f(int i = 100);

void main()

Trang 18

Ví dụ 2:

- Khai báo sau đây là sai:

void g(int a = 1, int b, int c = 3, int d = 4); vì các tham số ngầm định phải khai báo cuối danh sách tham số

- Khai báo sau đây là đúng:

void g(int a, int b=2, int c = 3, int d = 4);

- Với khai báo đúng trên, xét các lời gọi hàm sau

đây:

g(); // sai vì a không có giá trị mặc địnhg(10,20,30,40); // đúng vì đầy đủ tham số

g(10,20,,40); // sai vì sử dụng ngắt quãng

g(10); // đúng và nhận các giá trị mặc định của b,c,d là 2,3,4

g(10,20) ; // đúng và nhận các giá trị mặc định của c, d là 3,4

Trong khi khai báo các hàm thành phần của lớp, đặc biệt là constructor (constructor) ngời ta rất hay sử dụng các tham số ngầm định

Trang 19

9 Cấp phát và giải phóng bộ nhớ

Trớc hết về cú pháp của lệnh cấp phát và giải phóng

bộ nhớ, C++ đã cung cấp thêm 2 lệnh mới ngắn gọn và dễ dùng hơn là new và delete

Xét ví dụ sau đây:

char *s;

char tg[100];

int len;

/* Cấp phát bộ nhớ cho con trỏ s

kiểu char */ /* để có thể chứa

Mặc dù new và malloc đều dùng để chỉ đến địa chỉ

đầu của vùng nhớ xin cấp phát nhng giữa chúng vẫn có

Trang 20

{ int* ip = new int[0];

//trả lại giá trị không xác định của con trỏ

int* ip = (int*) malloc (0);

// trả lại giá trị NULL pointer

}

Qua ví dụ trên ta thấy toán tử new trả lại giá trị khác

0 của con trỏ thậm chí ta không đòi hỏi phải cấp phát bất

cứ một bytes nào trong bộ nhớ Giá trị này của con trỏ nếu

đợc sử dụng cho mục đích khác sẽ sinh lỗi trong chơng trình Ngợc lại hàm malloc trong trờng hợp này trả lại giá trị NULL, điều này có nghĩa là con trỏ cha trỏ đến bất cứ vị trí nào trong bộ nhớ

Cũng cần lu ý là trong C++, hàm malloc có kiểu trả lại là void* do đó khi sử dụng phải thực hiện việc chuyển

đổi kiểu tơng ứng với kiểu của đối tợng xin cấp phát bộ nhớ

Ngoài hai khác biệt trên về bản chất cả new và malloc đều dùng để cấp phát bộ nhớ động cho các biến trong quá trình thực hiện chơng trình và con trỏ trả lại theo hai cách này khi thành công đều không có gì khác biệt

Trong lập trình C++, toán tử new đợc a dùng vì nó mềm dẻo do khả năng định nghĩa chồng các toán tử của lớp

10 Các hàm tải bội (Overloaded function)

C++ đa ra một khả năng hoàn toàn mới và rất mạnh

so với C đó là khả năng định nghĩa chồng các hàm, nghĩa

là cho phép định nghĩa các hàm thực hiện các chức năng khác nhau nhng có cùng một tên Một hàm đợc định nghĩa chồng còn gọi là hàm tải bội (dịch từ cụm từ overloading)

Ngoài hàm tải bội, C++ còn cho phép toán tử tải bội

để bình thờng hóa các toán tử quen thuộc đối với một kiểu dữ liệu mới do ngời lập trình định nghĩa

Trang 21

Khi các hàm đợc tải bội thì phải tuân theo 2 nguyên tắc sau đây:

+ Các hàm phải khác nhau về số lợng tham số hoặc kiểu dữ liệu của các tham số

+ Kiểu giá trị của hàm không cho phép phân biệt các hàm đợc tải bội nếu các hàm này có danh sách tham số nh nhau

Khi gọi các hàm tải bội, C++ sẽ đối sánh danh sách tham số và kiểu thích hợp với các tham số thực sự để cho thực hiện hàm thích hợp trong số các hàm tải bội

Ví dụ 1: Tải bội hàm abs để tính giá trị tuyệt đối của

một số bất kỳ:

int abs(int i);

long abs(long l);

double abs(double d);

Khi đó, xét lời gọi các hàm sau đây:

abs(-10); // gọi hàm int abs(int i);

abs(-100000); // gọi hàm long abs(long l);

abs(-34.12); // gọi hàm double abs(double d);abs('a'); // gọi hàm int abs(int i);

Ví dụ 2: Tải bội hàm tự định nghĩa display để hiển

thị một giá trị có kiểu đơn giản bất kỳ:

void Display(char *string) {puts(string); }

void Display(long value) { printf("%ld",value); }void Display(double value) { printf("%lf",value); }void main(){ Display("\n Hello Mumy");

Display(123456789);

Display(3.1416);

Display(123); // sai }

Trang 22

11 Hàm inline

11.1 Nhắc lại macro trong ngôn ngữ C

- Macro (dịch theo nghĩa thông thờng là vĩ mô) hiểu theo nghĩa tin học là một lệnh riêng lẻ viết bằng một ngôn ngữ lập trình nhng kết quả là một chuỗi lệnh bằng ngôn ngữ máy tính

- Trong ngôn ngữ C cho phép tạo ra các macro để

đúng nh ý nghĩa của nó: cho phép tạo ra một hằng hoặc thậm chí tạo ra một hàm và nói chung tạo ra một tên thay thế (tên macro) để ghép macro này nh một đoạn trình mã máy vào chơng trình nguồn lúc thực hiện

- Trớc hết macro đợc định nghĩa bằng chỉ thị #define (và đợc hủy bỏ bằng #undef) Các chỉ thị #define (phép thay thế lệnh), #include (phép chèn tệp), #if (phép lựa chọn các dòng lệnh để biên dịch): đều là các chỉ thị tiền xử lý, không phải là các câu lệnh thông thờng của chơng trình Khi một chơng trình C đợc biên dịch, trớc hết các chỉ thị tiền xử lý sẽ chỉnh lý văn bản chơng trình nguồn, sau đó bản chỉnh lý này mới đợc dịch Các chỉ thị tiền xử lý, do đó làm cho chơng trình ngắn gọn hơn, giúp cho việc tổ chức biên dịch, gỡ rối chơng trình hiệu quả hơn

- Có 2 loại macro: macro thay thế đơn giản và macro thay thế theo đối (nh các hàm)

a)Macro đơn giản

#define tên_macro biểu_thức

có tác dụng thay thế tên_macro bằng biểu_thức

đứng sau nó Khi biểu thức ký tự dài có thể thêm một dấu \ trớc khi xuống dòng Trớc khi dùng lại tên_macro cho một biểu_thức khác thì phải destructor nó bằng chỉ thị

#undef tên_macro

Ví dụ 1:

Trang 23

(1) Khi định nghĩa biểu thức chứa phép toán cần đặt

biểu thức trong dấu ngặc đơn

Ví dụ 3: nếu viết

(2) Khi định nghĩa một macro nh một đoạn chơng

trình thì phải viết đoạn chơng trình trong khối lệnh { }

Trang 24

Có thể dùng macro có đối để định nghĩa hàm Khi

đó có một số điểm chú ý sau đây:

- Đối của macro có thể không cần khai báo kiểu cụ thể

- Tên hàm (macro) phải viết liền với dấu mở ngoặc bắt đầu khai báo đối

- Tất cả các đối hình thức trong thân hàm (macro) phải viết trong ngoặc đơn

Khi biên dịch, chơng trình sẽ biên dịch sẽ thay

tich(x+y,z) bằng x+y*z nh vậy sẽ không nhận đợc tích (x+y)*z nh mong muốn Vậy phải khai báo lại là:

#define tich(a,b) (a)*(b)

11.2 Hàm inline

Trong ngôn ngữ C++, hàm inline có cách hoạt động giống nh một macro trong ngôn ngữ C Nghĩa là các hàm inline sẽ đợc thay thế trực tiếp thành dãy lệnh mã máy tại chỗ gọi nó trong chơng trình lúc thực hiện

Ưu điểm của macro và inline là ở chỗ nó cho phép trình bầy chơng trình ngắn gọn và quan trọng là cho phép thực hiện nhanh hơn các hàm thông thờng Bởi vì mỗi lần gọi hàm inline (hoặc macro), trình biên dịch sẽ ghép trực

Trang 25

tiếp câu lệnh mã máy của nó tại vị trí gọi nó trong chơng trình (mã máy) lúc thực hiện và không đòi hỏi các thủ tục

bổ sung khi gọi hàm và trả giá trị về, nói cách khác không

có cơ chế quản lý lời gọi và trả về (không cần lu ngữ cảnh)

nh đối với các hàm thông thờng

Nhợc điểm của inline (và macro) là khi chúng quá lớn và gọi thờng xuyên thì kích thớc chơng trình sẽ tăng lên rất nhanh Vì mỗi lần gọi inline (hoặc macro) thì các chỉ thị tơng ứng sẽ đợc sinh ra (không có cơ chế lu ngữ cảnh để giải phóng bộ nhớ) do đo chí phí lu trữ tăng lên khi gọi hàm nhiều lần Vậy inline và macro tiết kiệm thời gian nhng không tiết kiệm bộ nhớ, cho nên thân các hàm inline không nên chứa các cấu trúc lặp

Việc sử dụng inline trong C++ tốt hơn macro trong

C ở chỗ hàm inline không cần phải viết các tham số trong dấu ngoặc nh đối với các hàm mà macro mô tả

Ví dụ nếu định nghĩa một macro

#define square(x) { x++*x++;}

thì lời gọi square (a) sẽ sinh ra biểu thức a++*a++ làm thay đổi giá trị của a tới hai lần và hơn nữa lời gọi square(3) sẽ không đợc chấp nhận vì không đợc phép tăng giảm đối với hằng số

Hàm inline đợc định nghĩa và sử dụng nh một hàm bình thờng, điểm khác nhau duy nhất là phải đặt mô tả inline trớc khai báo hàm

Cuối cùng, cần nhớ rằng giống nh macro, đặc tả inline là một yêu cầu chứ không phải là một chỉ thị Nếu vì một lý do nào đó mà trình biên dịch không đáp ứng đợc yêu cầu của inline (chẳng hạn nh bên trong inline có cấu trúc lặp) thì yêu cầu của inline bị bỏ qua và nó đợc biên dịch nh một hàm bình thờng (đây cũng là một điểm tiến bộ của inline so với macro)

Ví dụ:

Trang 26

12 Khả năng vào ra mới của C++

12.1 Tổng quan về stream trong C++

Nhìn lại C thấy thấy rằng C sử dụng rất nhiều hàm

để nhập và xuất dữ liệu ví dụ nh: printf(), scanf(), sprintf(), sscanf(), Các hàm này đợc khai báo trong file tiêu đề stdio.h Về một khía cạnh, chúng không nhất quán về thứ

tự và ngữ nghĩa của các tham số

C++ đa ra streams thông qua các lớp và gọi các lớp này là th viện các dòng nhập/xuất Streams tạo ra một khả năng rất mạnh cho phép sửa đổi và mở rộng và vì vậy có thể nhập/xuất đối với các kiểu dữ liệu mới do ngời dùng

định nghĩa

Các dòng nhập (istream) cho phép nhập dữ liệu vào stream, các dòng xuất (ostream) cho phép xuất dữ liệu từ stream Th viện các dòng nhập/xuất là một cấu trúc cây các lớp và chúng ta sẽ nghiên cứu sau

Trang 27

Trong tệp tiêu đề iostream.h C++ định nghĩa 2 đối

tợng cin và cout tơng ứng là hai thiết bị chuẩn vào/ra và

đ-ợc sử dụng cùng với hai toán tử tải bội >> (vào) và << (ra)

Thông thờng, ta hiểu cin là bàn phím còn cout là màn hình

12.2 Ghi dữ liệu lên thiết bị ra chuẩn (màn hình) bằng

đó Toán tử << có khả năng tải bội mà trớc hết nó đúng đối với các kiểu sau đây:

1 Kiểu dữ liệu cơ sở: char, int, float, double

Trang 28

ợc xem xét trong lần đọc sau.

+ Đối với xâu ký tự, dấu phân cách cũng là SPACE, TAB, CR còn đối với ký tự, dấu phân cách là ký tự CR Trong trờng hợp này không có khái niệm "ký tự không hợp lệ" Mã sinh ra do bấm phím Enter của lần nhập trớc đó vẫn đợc xem xét cho lần nhập xâu ký tự tiếp theo, do đó sẽ

có thể không nhập đợc ký tự mong muốn Giải pháp đặt ra

là trớc mỗi lần nhập xâu ký tự hoặc ký tự ta làm rỗng bộ

đệm bàn phím bằng một trong 2 lệnh sau đây: fflush(stdin); // trong file tiêu đề stdio.h

cin.clear(); // hàm thành phần của lớp định nghĩa

đối tợng cin

+ Trong trờng hợp muốn nhập xâu ký tự có cả dấu cách thì nên dùng lệnh gets(), khai báo trong file tiêu đề stdio.h

Trang 29

cout<<"nhap mot xau: "; gets(s)

cout<<"xau vua nhap: "; puts(s);

}

Streams đợc sử dụng hoàn toàn độc lập với stdio

nh-ng việc sử dụnh-ng đồnh-ng thời hai th viện này có thể làm phát sinh ra một số vấn đề, chẳng hạn sẽ không làm xuất ra dữ liệu theo đúng thứ tự mong muốn

Trang 30

Bài 3 Một số khái niệm cơ bản của lập trình hớng đối tợng

1 Khái niệm đối tợng (Object)

Đối tợng là mô hình của thực thể, bao gồm:

- Thông tin mô tả đối tợng (dữ liệu), gọi là trạng thái (status) của đối tợng

- Các hàm tác động lên đối tợng làm thay đổi trạng thái của đối tợng, gọi là phơng thức (method) của đối tợng

Dữ liệu và các hàm của đối tợng gắn liền với nhau

- Lớp là kiểu dữ liệu đợc định nghĩa bởi ngời dùng nên nó cũng có các tính chất nh một kiểu dữ liệu cơ sở

Ví dụ nếu A là lớp thì viết A a; cũng giống nh khi viết int x; Tức là a là một biến kiểu A, tuy nhiên ta sẽ gọi

là a là một đối tợng của lớp A và lệnh này gọi là lệnh tạo lập đối tợng

3 Trừu tợng hoá dữ liệu và bao gói thông tin

(Abstraction and Encapsulation)

- Việc đóng gói dữ liệu và các hàm gắn với nó vào một đơn vị cấu trúc (tức là một lớp các đối tợng) đợc xem

nh một nguyên tắc bao gói thông tin Nguyên tắc bao gói dữ liệu ngăn cấm sự truy nhập trực tiếp trong lập trình gọi

là sự che dấu thông tin.

Trang 31

- Trừu tợng hoá dữ liệu là cách biểu diễn những đặc tính chung nhất của các đối tợng có cùng một bản chất, bỏ qua những thông tin chi tiết của từng đối tợng riêng lẻ Trong lập trình, lớp đợc sử dụng nh kiểu dữ liệu trừu tợng

và nâng lên mức khuôn mẫu lớp Phơng pháp lập trình ớng đối tợng bao gồm cả trừu tợng hoá dữ liệu và trừu tợng hoá chức năng

h-4 Sự kế thừa (Inheritance)

4.1 Khái niệm sự kế thừa

- Sự kế thừa là quá trình mà các đối tợng của lớp này đợc quyền sử dụng một số tính chất của các đối tợng của các lớp khác Lớp trên gọi là lớp cơ sở (base class), lớp

mới nhận đợc gọi là lớp dẫn xuất (derivative class)

- Nguyên lý kế thừa tạo ra cấu trúc phân cấp các lớp (đồ thị dạng cây)

- Trong lập trình hớng đối tợng, khái niệm kế thừa kéo theo ý tởng sử dụng lại, nghĩa là từ một lớp đã xây dựng, ta có thể bổ sung một số tính chất riêng để tạo ra một lớp mới mà không làm thay đổi những cái đã có

Trang 33

5 Sự đa hình và sự tải bội (Polymorphism and

Oveloading)

5.1 Khái niệm về sự đa hình (sự tơng ứng bội)

Sự đa hình (Polymorphism) đợc hiểu một cách trừu tợng là khả năng một khái niệm có thể xuất hiện ở nhiều dạng khác nhau

Hàm và toán tử tải bội là một ví dụ của tính đa hình, tuy nhiên, sự tải bội mà chúng ta nhìn thấy ở đây là sự liên kết tĩnh Hàm đợc chọn ở đây là trong thời gian dịch chơng trình và điều này làm giới hạn tính đa hình Trong ngôn ngữ C++, các hàm đợc chọn trong khi chạy chơng trình và

đây là một kỹ thuật trong sự kế thừa ở C++ Sự đa hình

hiểu theo cách trên có lẽ nên dịch là sự tơng ứng bội thì

thích hợp hơn vì nó nhằm trả lời câu hỏi: Ngoài cơ chế cho phép tải bội của các hàm và toán tử trong một lớp, thì một con trỏ đối tợng sẽ liên kết với hàm nào trong các lớp có quan hệ kế thừa mà các hàm này có chung đặc tính (cùng tên và cùng tham số, kiểu tham số và kiểu của hàm) ? Rõ

Tơng ứng bội đóng vai trò quan trọng trong việc tạo

ra các đối tợng có cấu trúc bên trong khác nhau nhng có khả năng cùng dùng chung một giao diện bên ngoài (nh tên gọi) Điều này có nghĩa là một lớp tổng quát các phép toán

Trang 34

đợc định nghĩa theo các thuật toán khác nhau nhng có khả năng sử dụng theo cùng một cách giống nhau Tơng ứng bội là mở rộng khái niệm sử dụng lại trong nguyên lý kế thừa

Ví dụ:

Hàm VE() là hàm tơng ứng bội và nó đợc xác định tùy theo ngữ cảnh khi sử dụng.Trong lập trình hớng đối t-ợng với C++, tơng ứng bội có 2 loại:

Loại 1: Tơng ứng bội trong thời gian dịch chơng

trình: Đó là sự cho phép định nghĩa và thực hiện các toán

tử tải bội (operator overloading) và các hàm tải bội (function overloading) Ví dụ một toán tử gốc của ngôn ngữ là phép +, chỉ có thể thực hiện đợc đối với kiểu dữ liệu cơ sở nh int, float, double, char chứ không thể thực hiện

đối với các kiểu dữ liệu do ngời dùng định nghĩa, ví dụ nh

Tương ứng bội

Tương ứng bội trong

thời gian dịch chương Tương ứng bội trong thời gian chạy chương trình

HINH_HOC VE()

HINH_TRON()

VE(TRON) VE(DA_GIAC)DA_GIAC DUONG_THANG

VE(D_THANG)

Trang 35

các số phức, các vector, các ma trận cùng kích thớc Nh vậy, lập trình hớng đối tợng cho phép giữ nguyên ký hiệu phép cộng + để định nghĩa bổ sung phép cộng cho các kiểu dữ liệu mới Khi đó ta có định nghĩa chồng toán tử, hay toán tử đó có khả năng tải bội Tơng tự có thể định nghĩa các hàm cùng tên trong một lớp nhng thực hiện các chức năng khác nhau Ví dụ nh các constructor của lớp là một tr-ờng hợp của hàm tải bội; chuyển đổi từ kiểu lớp sang kiểu cơ sở đợc coi là hàm tải bội Nếu hiểu theo nghĩa "phép toán là tác động lên dữ liệu, làm thay đổi dữ liệu" thì toán

tử tải bội và hàm tải bội đều là các phép toán tải bội

Loại 2: tơng ứng bội trong thời gian chạy chơng

trình Đó là sự cho phép định nghĩa và thực hiện các hàm

cùng tên, chung đặc tính trong lớp khác nhau có quan hệ

kế thừa nhau Nếu nh tơng ứng bội trong thời gian dịch

ch-ơng trình quan tâm đến các hàm và toán tử cùng tên trong một lớp thì tơng ứng bội trong thời gian chạy chơng trình quan tâm đến những hàm và phép toán cùng tên và chung

đặc tính giữa các lớp có quan hệ kế thừa và cách ứng xử của các đối tợng tơng ứng nh thế nào khi gọi thực hiện các hàm này

5.2 Liên kết tĩnh và liên kết động

Tơng ứng bội trong thời gian dịch chơng trình và

t-ơng ứng bội trong thời gian chạy cht-ơng trình liên quan

đến khái niệm liên kết tĩnh và liên kết động (có tài liệu

còn gọi liên kết tĩnh là liên kết sớm hay ràng buộc sớm - Early Binding; và gọi liên kết động là liên kết muộn hay ràng buộc muộn - Late Binding)

Trong chơng trình hớng đối tợng với C++, cần phải trả lời câu hỏi: Một con trỏ đối tợng sẽ liên kết với hàm nào trong các lớp có quan hệ kế thừa mà các hàm này có chung đặc tính?

Trang 36

- Nếu mối liên kết giữa đối tợng với hàm đó đã có thể xác định đợc ngay từ khi dịch chơng trình và sẽ không thay đổi trong suốt thời gian chạy chơng trình thì đợc gọi

là liên kết tĩnh Nh vậy các phép toán tải bội trong một lớp

và các hàm cùng đặc tính giữa các lớp nếu không có một chỉ định đặc biệt nào đó (ở đây là cài đặt cơ chế hàm ảo) thì đều là các phép toán đợc thực hiện theo sự liên kết tĩnh

- Ngợc lại, nếu mối liên kết này chỉ có thể xác định

đợc tại những thời điểm khác nhau lúc chạy chơng trình thì gọi là liên kết động Liên kết động đợc giải quyết bằng cơ chế hàm ảo (virtual function) Cơ chế hàm ảo cho phép

định nghĩa các hàm trừu tợng ở lớp trên và cài đặt cụ thể ở các lớp dới, sau đó, lúc chạy chơng trình, con trỏ đối tợng

sẽ tùy theo ngữ cảnh mà gọi hàm nào trong các lớp có quan hệ kế thừa

Những nhận xét mở đầu này sẽ đợc trình bầy cụ thể khi nghiên cứu về sự kế thừa

Trang 38

- Những thành phần đợc khai trong lớp đợc chia thành 2 nhóm:

+ Những thành phần private chỉ có thể đợc truy nhập bởi các hàm thành phần khác bên trong chính lớp đó, tức là chúng chỉ đợc sử dụng bên trong thân các hàm thành phần của lớp Những thành phần private do đó không thể truy nhập bởi những hàm bên ngoài lớp thậm chí không thể truy nhập thông qua chính đối tợng thuộc lớp đó (thông qua toán tử chấm: ".", là toán tử xác định thành phần của đối t-ợng)

+ Những thành phần public có thể đợc truy nhập bởi các hàm thành phần khác bên trong lớp và các hàm bên ngoài lớp Nếu truy nhập bởi các hàm bên ngoài lớp thì phải sử dụng thông qua đối tợng của lớp Các đối tợng thuộc lớp sẽ truy nhập tới các thành phần public thông qua toán tử xác định "."

- Các hàm bên ngoài lớp tức là các hàm thành phần của lớp khác và các hàm bình thờng trong chơng trình, không thuộc lớp nào cả (gọi là các hàm ngoại lai)

Vùng private

Vùng public

Datafunction

Datafunction

Trang 39

{ cout<<"Enter name: "; gets(name);

cout<<"Enter age: "; cin>>age; }

Trang 40

{ cout<<"Nhap ho ten sinh vien: "; gets(hoten);

cout<<"Nhap nam sinh: "; cin>>namsinh; }

void SINHVIEN::xem()

{ cout<<"Ho ten: "<<hoten<<endl;

cout<<"Nam sinh: "<<namsinh<<endl;}

Ngoài thành phần private và public, trong lớp còn có thành phần protected đợc dùng trong quan hệ kế thừa giữa các lớp, ta sẽ nghiên cứu sau

Ngày đăng: 14/11/2012, 15:36

HÌNH ẢNH LIÊN QUAN

Bớc 3: Xây dựng bảng các thành phần lớp và quan - Lập trình hướng đối tượng
c 3: Xây dựng bảng các thành phần lớp và quan (Trang 156)
- Vẽ một màn hình caro mầu xanh đờng kẻ xanh d- d-ơng - Lập trình hướng đối tượng
m ột màn hình caro mầu xanh đờng kẻ xanh d- d-ơng (Trang 157)
- LODAT - HTHANG  - Lập trình hướng đối tượng
- LODAT - HTHANG (Trang 166)
Bớc 3: Xây dựng bảng các thành phần lớp và quan - Lập trình hướng đối tượng
c 3: Xây dựng bảng các thành phần lớp và quan (Trang 166)

TỪ KHÓA LIÊN QUAN

w