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

Ngôn ngữ lập trình C++ từ cơ bản đến hướng đối tượng part 7 pptx

51 239 2
Tài liệu được quét OCR, nội dung có thể không chính xác

Đ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 đề Ngôn Ngữ Lập Trình C++ Từ Cơ Bản Đến Hướng Đối Tượng Part 7
Trường học University of Information Technology
Chuyên ngành Computer Science
Thể loại Bài giảng
Năm xuất bản 2023
Thành phố Ho Chi Minh City
Định dạng
Số trang 51
Dung lượng 571,73 KB

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

Nội dung

Phương pháp trên không thể thực hiện được trong các trường hợp sau: ® Tham số đang chờ đợi lại được dùng để khởi tạo các thành phần khác hoặc được dùng như các tham số truyền của lớp khá

Trang 1

Hide(); // Xóa đường tròn cũ

X = NewX; // Thiết lập vị trí mới

H Khoi tao dé hoa

int graphdriver = DETECT;

Trang 3

Phương pháp trên không thể thực hiện được trong các

trường hợp sau:

® Tham số đang chờ đợi lại được dùng để khởi tạo các

thành phần khác hoặc được dùng như các tham số

truyền của lớp khác

* Tham sé dang ché đợi được khối tạo được khai báo theo kiểu private trong lớp cơ sở (chỉ có thể trì hoãn việc khởi tạo các thành phần kiểu publie hoặc protected),

8.1.3 Lép hat giéng (Seed class)

Cac lép trong C** duge thiét ké dé thue hién mot mue dich

nào đó và thông thường từ các lớp cơ sở đến các lớp dẫn xuất,

mức độ phức tạp của chúng ngày càng tăng Một trong các

mục đích của việc dẫn xuất một lớp từ một lớp khác là để tránh việc trùng lặp khi viết chương trình Khi có nhiều lớp khác nhau được dẫn xuất từ một lớp khác thì lớp cơ sở này thường rất đơn giản và nó thường chứa các đặc điểm chung của tất cả các lớp dẫn xuất Các lốp mà mục đích được xây dựng chỉ nhằm chia sẻ các đoạn mã cho các lớp dẫn xuất được

307

Trang 4

gọi là các lớp hạt giống (seed class) Cần lưu ý là mặc dù các lớp này không cần phải thiết kế như một lớp trừu tượng (xem chương X) nhưng việc sử dụng để khởi tạo các đối tượng cũng

hầu như không đem lại lợi ích gì trong khi xây dựng chương trình Hãy xét đoạn chương trình sau:

BookSelf(int, int, int, int);

int GetColor( ) { return color;}

int GerWidth () { return width;}

int GetHeight( ) { return shelver;}

Desk(int, int, int, int);

int 6etColor( } { return color;}

int GetWidth( } { return width;}

int 6etHeight( ) { return shelves;}

int GetDrawers( ) { return drawers;}

int GetMaterial( ) { return material,}

308

Trang 5

Doan chuong trinh trén cé hai lép: BookShelf va Desk Hai

lớp này có rất nhiều đặc điểm chung nhưng vẫn tổn tại các điểm khác nhau giữa chúng Constructor của BookSelƒ có bốn đối số trong khi constructor cia Desk lai cé nam đối số Thêm vào đó thứ tự xuất hiện của các đối số trong hai construefor này cũng có

những điểm khác nhau Để tránh viết lại các điểm được xem là giống nhau giữa hai lớp, ta có thể xây dựng một seed class - lớp Furniture

Trang 6

310

int width, height;

public:

Furniture(int, int, int);

int GetColor() { return color;}

int GetWidth() { return width;} int GetHeight() { return shelves;}

BookSelf{int, int, int, int);

int GetShelves(} { return shelves;}

Desk( int, int, int, int, int};

int GetDrawers() { return drawers;} int GetMaterial(} { return material;} }

Trang 7

BookSelt::BookSelf( int c, int w, int h, int s) : Furniture(c, w, h)

hiện việc chuyển kiểu từ lớp 8 sang lớp A Tuy vậy điều ngược lại là không được phép

311

Trang 8

Trong ví dụ này, khi hàm foo(bp) được gọi, trình biên dịch

sẽ thực hiện việc chuyển bp từ kiểu B sang kiểu A và sau đó truyền tham số cho hàm foo(A* object)

312

Trang 9

8.1.5 Sử dụng phạm vi trong lớp

"Theo nguyên tắc sử dụng hàm chẳng, trong C' các dữ liệu

và hàm thành phần thuộc các lớp khác nhau có thể được đặt

cùng tên (thậm chí có cùng đối số hoặc kiểu của các đối số trong trường hợp hàm thành phần) Như vậy trong một kiểu dẫn xuất

có thể tồn tại các dữ liệu và hàm thành phản trùng với các dữ liệu và hàm trong lớp cơ sở (trùng tên, trùng đối số, trùng kiểu của các đối số) Trong trường hợp này để có thể gọi chính xác một biến hoặc hàm thuộc lớp cơ sở từ một đối tượng thuộc lớp dẫn xuất C** sử dụng toán tử phạm vi (Scope Resolution)

Một số người lập trình thường nhằm lẫn và không xác định

được giá trị của y khi thực hiện hàm b.foof) Lép B cé 2 hàm

fooQ Một hàm được thừa kế từ lớp Á và một hàm là của chính

313

Trang 10

lớp B Trong trường hợp trên z có giá trị là 1 và y có giá trị là 2 Trình biên dịch đã gọi chính xác các hàm thậm chí các hàm đó trùng tên nhau nhờ sử dụng quy tắc về phạm vi Theo quy tắc

này thì nếu tên của các biến hoặc hàm trong lớp cơ sở được khai báo lại trong lớp dẫn xuất thì tên trong lớp dẫn xuất sẽ che khuất tên tương ứng trong lớp cơ sở Điều này cũng giống như khi sử dụng phạm vi của các biến trong từng vùng v.v

Tuy vậy, trong C** cũng tổn tại nhiều điểu khác biệt Ta có

thể bắt buộc trình biên dịch “nhìn” ra ngoài phạm vi hiện thời

và truy nhập đến các tên đã bị che khuất trong phạm vì đó bằng

cách sử dụng các toán tử phạm vi (Scope Resolution Operator) Các biến và hàm được gọi trong bị che khuất có thể được gọi theo

cách sau:

<Tên láp::<Tên biến hoặc hàm>;

Đoạn mã sau sẽ minh họa cho việc sử dụng toán tử phạm vị: class At

int f(}{ return A::foo();}

j/ Sử dụng toán tử phạm vi để gọi fooQ thudc A

Trang 11

8.1.5 Sử dụng phạm ví trong lớp

Theo nguyên tắc sử dụng hàm chồng, trong C** các dữ liệu

và hàm thành phần thuộc các lớp khác nhau có thể được đặt

cùng tên (thậm chí có cùng đối số hoặc kiểu của các đối số trong

trường hợp hàm thành phần) Như vậy trong một kiểu dẫn xuất

có thể tổn tại các đữ liệu và hàm thành phần trùng với các dữ liệu và hàm trong lớp cơ sở (trùng tên, trùng đối số, trùng kiểu của các đối số) Trong trường hợp này để có thể gọi chính xác một biến hoặc hàm thuộc lớp cơ sở từ một đối tượng thuộc lớp dan xuat C** st dung toan tu pham vi (Scope Resolution)

Trang 12

lớp B Trong trường hợp trên z có giá trị là 1 và y có giá trị là 2

"Trình biên địch đã gọi chính xác các hàm thậm chí các hàm đó

trùng tên nhau nhờ sử dụng quy tắc về phạm vị Theo quy tác này thì nếu tên của các biến hoặc hàm trong lớp cơ sở được khai báo lại trong lớp đẫn xuất thì tên trong lớp dẫn xuất sẽ che khuất tên tương ứng trong lớp cơ sở Điểu này cũng giống như khi sử dụng phạm vi của các biến trong từng vùng v.v

Tuy vậy, trong C'* cũng tổn tại nhiều điểu khác biệt Ta có

thể bắt buộc trình biên dịch “nhìn” ra ngoài phạm vi hiện thời

và truy nhập đến các tên đã bị che khuất trong phạm vị đó bằng cách sử dụng các toán tử phạm vi (Scope Resolution Operator)

Các biến và hàm được gọi trong bị che khuất có thể đượe gọi theo

cách sau:

<Tên lớp::<Tên biến hoặc hàm>;

Đoạn mã sau sẽ minh họa cho việc sử dụng toán tử phạm vị:

int f(}{ return A::foo();}

J Sir dung toán tử phạm vi để gọi foo() thuộc A

}

Trong trường hợp này, khi gọi hàm Ö: ƒ#) thi ham foo() của lớp A sẽ được gọi và thực hiện Việc sử dụng toán tử phạm vi không những chỉ được thực hiện bên trong một hàm thuộc một

314

Trang 13

lớp mà còn có thể được thực hiện trong thời gian gọi hàm Hãy xét ví dụ dưới đây:

Trong trường hợp chương trình có sử dụng nhiều mức độ

thừa kế khác nhau, toán tử phạm vi vẫn cho phép truy nhập đến

thành phần của bất cứ lớp cơ sở nào Hãy xét cấu trúc thừa kế sau và chương trình minh họa cho cấu trúc này:

Trang 14

int foo(){ return 4;}

int #1(){ rerturn A::foo();}

7 Cho phép sử dụng toán tử phạm vi

int f2(1{ rerturn B:foo();}

j{ Cho phép sử dụng toán tử phạm vi

int £3(){ rerturn C::foo();}

if Cho phép sir dung toán tử phạm ví

int £4(}{ rerturn D::foo(};}

Trang 15

Như ta đã biết, một trong những nguyên nhân chính dẫn

đến việc dẫn xuất một lớp từ một lớp cơ số là đo lớp cơ sở có chứa nhiều hàm hoặc đữ liệu mà lớp dân xuất cần sử dụng đến Tuy vậy, để có thể đáp ứng được các yêu câu của lớp dẫn xuất các ham nay còn cần phải phát triển thêm, Việc viết lại toàn bộ các hàm đó trong lớp dẫn xuất sẽ làm phí tổn nhiều thời gian Để tránh vấn để này, C'* cho phép sử dụng lại các đoạn mã của hàm được viết trong lớp cơ sở qua việc mở rộng chúng trong lớp

dẫn xuất Điều này được thực hiện thông qua việc định nghĩa lại các hàm trong lớp cơ sở ở lớp dẫn xuất Hãy xem xét đoạn chương trình dùng để thiết kế một hình tượng (con) cho một nút bấm ấn - thả (puah - button)

class Box {

int left, top;

317

Trang 16

int width, hight;

Trang 17

const int QUTLINE_HEIGHT = 20;

const int BUTTON_WIDTH = 32;

const int BUTTON_HEIGHT = 16;

Outline=new Box(x,y,OUTLINE_WIDTH OUTLINE_HEIGHT);

int bx = x+ (OUTLINE_WIDTH - BUTTON_WIDTH)/2;

int by = y+(OUTLINE_HEIGHT - BUTTON_ HEIGHT)/2,

Button=new Box(bx,by, BUTTON_WIDTH,BUTTON_HEIGHT)

thước khác nhau Thay vì phải viết lại các công việc này, trong lớp PushButton có định nghĩa lại hàm Display trong lép co sd, hầm này có cùng tên với hàm đã được định nghĩa trong lớp cơ sd Lớp PushButton cố thể được dùng trong ví dụ sau:

319

Trang 18

với một hàm khác dùng để hiển thị chuỗi văn bản trong nút,

Điểu này sẽ được giải quyết nếu ta tạo một lớp dẫn xuất từ lớp PushButton va mé réng ham Display cho lớp đó Lớp dẫn xuất

mới được gọi là PwshButtonWHhTile và sẽ sử dụng hàm

PushButton::Display() dé hién thị hình tượng và sau đó sẽ viết

đồng tiêu để lên trên hình tượng đó Có thể biểu diễn sự thừa kế 320

Trang 19

của các lớp thông qua cấu trúc cây ở hình 8.3 Trong cấu trúc cây

này, 7ex là một lớp mới không dẫn xuất từ PushButton và dùng

để xuất một xâu ký tự tại điểm có tọa độ (x,y)

Sau đây là đoạn mã của các lớp:

Hinh 8.3

Trang 20

Title = new Text(x,y,legend};

Trang 21

int gdrv = DETECT, gmode, Err;

Trong ví dụ này, hàm được mở rong cua PushButton là

ĐisplayQ trong lớp mới PushButtonWithTile Ham này không

chỉ vẽ nút bấm (PushButton) mà còn hiển thị dòng mô tả tác

dụng của PushButton nay Trong lép PushButtonWithTile, ham

Display( cha lớp này sử dụng toán tử phạm vi để truy nhập đến

các hàm ¿siay() có cùng tên trong các lớp cơ sở PushButton và Text

8.1.7 Thu hẹp tác động của các hàm thừa kế

Các lớp cơ sở thường chứa các hàm hoặc dữ liệu gần giống

với các hàm và đữ liệu mà lớp dẫn xuất có thể sử dung Goi la

323

Trang 22

gần giống vì trong nhiều trường hợp các hàm trong lớp cơ sở có thể chưa đạt được yêu cầu của lớp dẫn xuất Ở trên chúng ta đã xét trường hợp khi cần mở rộng các tác động của các hàm này trong lớp dẫn xuất Trong trường hợp các hàm trong lớp cd SỞ có chứa các tác động không cân thiết trong lớp dẫn xuất, các tác động này cần phải được loại bỏ Trong C**, các lớp dẫn xuất cũng

có thể hạn chế các tác động của lớp cơ sở trên lớp của mình Để

mình họa cho điều này, hãy quay lại ví dụ trên với hình dạng

của PushButton- mới không có hình chữ nhật ở bên trong

Để đạt được muc dich nay, rd rang PushButton: :DisplayO

cân phải được thay đổi để loại bổ tác động không cần thiết - vẽ

thêm một hình chữ nhật ở bên trong Có thể thực hiện điểu này

nếu sử dụng một lớp mới dẫn xuất từ PushBuHon - lớp

SimplePushButton Trong trường hợp này, các lớp được định nghĩa lại như sau:

Trang 23

thay đổi nhỏ trong lớp SừnplePushButton, hàm sẽ ngăn không

có các đối tượng của lớp SửnplePushButton biển thị hình chữ

nhật bên trong Điều cần nói ở đây là để đạt được mục đích mới

này, người lập trình không cần thực hiện bất cứ một sự thay đổi

nào trong lớp cơ sở Đây là một điểm rất quan trọng bởi vì các

lớp cơ sở thường chỉ có thể bị thay đổi bởi chính người cung cấp các lớp đó Nguyên nhân ở đây là khi được cung cấp cho người sử

dụng, các lớp này thường đã được biên dịch dưới dạng file Obj 8.2 THỪA KẾ BỘI (MULTIPLE INHERITANCE)

Trong cuội

sống, sự kết hợp giữa cha và mẹ sẽ tạo cho con cái thêm nhiều đặc tính phong phú: đó là khả năng thích nghỉ hơn với điều kiện của cuộc sống và khả năng chọn lọc những đặc tính tốt của cha và mẹ Các lớp dẫn xuất trong C'* không chỉ bị hạn chế bởi một lớp cơ sở duy nhất mà còn có thể thừa kế nhiều

325

Trang 24

lớp cø sở khác nhau Khi đó lớp dẫn xuất sẽ thừa kế tất cả các đặc tính mà mỗi lớp cơ sở có được Sự thừa kế này được gọi là

thừa kế bội và mặc dù có thể đẫn đến sự phức tạp trong ngôn ngữ cũng như đối với trình biên dịch đặc tính này cũng mang lại

rất nhiều điều thuận lợi trong khi thiết kế chương trình

Hãy xét một lớp RoundTable, lớp này không chỉ có các đặc

tính của lớp Tøöie mà còn phải có các đặc tính của lép Circle chứa các đặc tính của hình dạng bao quanh Sự thừa kế này có thể được mô tả qua cấu trúc cây sau:

Trang 25

RoundTable(float h, float r, int c);

int Color( }{ return Color;}

b

RoundTable::RoundTable(float h, float r, int c):

Cirle(r),Table(h) {

prinf(®n Các đặc tinh cia bang 18 :”);

printfC^n Chiều rong =f”, table.Height());

printf(‘An Diện tich =%f”, table Area());

printf(‘An Mau =%d”, table.Color());

}

Trong vi du trén, lép RoundTable a4 trd thanh rat don gian

đo thừa hưởng rất nhiều đặc tính từ các lớp cơ sở Khi khai báo một lớp dẫn xuất nào đó mang tính thừa kế bội, cần khai báo các lớp cơ sở của nó Sau khi được khai báo, các lớp cd sở này có thể được truy nhập trực tiếp trong lớp đẫn xuất của chúng Sự truy

327

Trang 26

nhập này hoàn toàn tương tự giống như trong trường hợp thừa

kế đơn

Ham mưinQ) trong vi du trên gọi 8 hàm thành phần

RoundTabl eightQ, RoundToble::Ared() và RoundTubie:Color

mà không cần phân biệt chúng có phải là hàm thừa kế hay

không Phương pháp truy nhập này cũng được sử dụng trong

trường hợp thừa kế đơn

8.2.1 Thực hiện Constructor của các lớp cơ sở

Giống như trường hợp thừa kế đơn, các consirucfor của các

lớp cơ sở trong trường hợp thừa kế bội cần phải được gọi trước

construcior của lớp dẫn xuất Thứ tự gọi các consfruefor của các

lớp này sẽ phụ thuộc vào thứ tự khai báo của chúng trong lớp dẫn xuất Hãy xét lại lớp RoundTable:

class RoundTable:public Table, public Circle {

int Color;

public;

RoundTable(float hy floar int 7

int Color() { return Color;}

}

Các lớp cơ sở được khai báo trong lớp dẫn xuất có thứ tự lần

lugt 1a Table, Circle Nhu vay khi thé hiện một đối tượng thuộc lớp RoundTable, các construetor sẽ lần lượt được gọi theo thứ tự

Ngày đăng: 12/08/2014, 13:22

TỪ KHÓA LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm