Con trỏ this

Một phần của tài liệu Lập trình hướng đối tượng (Trang 55 - 74)

CHƢƠNG 2 ĐỐI TƢỢNG VÀ LỚP

2. THIẾT KẾ VÀ CÀI ĐẶT LỚP

2.4. Con trỏ this

Khi một hàm thành viên tham chiếu thành viên khác của lớp cho đối tƣợng cụ thể của lớp đĩ, làm thế nào C++ bảo đảm rằng đối tƣợng thích hợp đƣợc tham chiếu? Câu trả lời là mỗi đối tƣợng duy trì một con trỏ trỏ tới chính nĩ – gọi là con trỏ this – Đĩ là một tham số ẩn trong tất cả các tham chiếu tới các thành viên bên trong đối tƣợng đĩ. Con trỏ this cũng cĩ thể đƣợc sử dụng tƣờng minh. Mỗi đối tƣợng cĩ thể xác định địa chỉ của chính mình bằng cách sử dụng từ khĩa this.

Con trỏ this đƣợc sử dụng để tham chiếu cả các thành viên dữ liệu và hàm thành viên của một đối tƣợng. Kiểu của con trỏ this phụ thuộc vào kiểu của đối tƣợng.

Tĩm lại, con trỏ this là đại diện cho đối tƣợng hiện hành, đối tƣợng hiện hành là đối tƣợng đang yêu cầu phƣơng thức đĩ thực hiện.

Ví dụ một phƣơng thức tính tổng hai phân số của lớp PhanSo sẽ đƣợc viết nhƣ sau:

PhanSo TongPS(PhanSo x) {

Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 55 tong.tu = thistu * x.mau + x.tu*thismau;

tong.mau = thismau * x.mau; return tong;

}

Giả sử ta cĩ hai phân số x, y. Muốn tính tổng x và y chúng ta gọi y.TongPS(x). Nhƣ vậy phƣơng thức TongPS() sẽ đƣợc gọi thực thi và nhiệm vụ là tính tổng của x và y. Do đĩ con trỏ this trong trƣờng hợp này chính là y – là đối tƣợng hiện hành.

2.5. Con trỏ đối tƣợng

Khai báo sử dụng con trỏ đối tƣợng. SinhVien *p;

p= new SinhVien;

Để gọi các phƣơng thức của đối tƣợng p thì sử dụng tốn tử “”, chẳng hạn nhƣ pXepLoai().

Lƣu ý khi nào khơng sử dụng nữa thì nhớ hủy vùng nhớ đã cấp phát cho p bằng câu lệnh delete p;

Khi cấp phát bằng tốn tử new thì phƣơng thức khởi tạo của lớp sẽ đƣợc gọi và khi hủy đối tƣợng bằng tốn tử delete thì phƣơng thức hủy của lớp sẽ đƣợc gọi.

2.6. Đối tƣợng thành phần

Khái niệm

Một đối tƣợng lại là một thành phần thuộc tính của một lớp khác, đối tƣợng này gọi là đối tƣợng thành phần. Lớp cĩ đối tƣợng thành phần đƣợc gọi là lớp bao.

Cách xây dựng phương thức khởi tạo cho lớp bao

Cú pháp:

TenLopBao(DS cac tham so):DTThanhPhan1,DTThanhPhan2,.. {

// khởi tạo cho các thuộc tính cịn lại khơng phải là đối tƣợng thành phần

}

Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 56

Truy xuất thành phần của đối tượng thành phần

Việc truy xuất đến thuộc tính (đối tƣợng thành phần) trong lớp bao theo quy tắc sau:

- Khơng thể nào truy xuất đƣợc thành phần private của đối tƣợng thành

phần trong lớp bao

- Đƣợc phép truy xuất đến thành phần public của đối tƣợng thành phần

trong lớp bao

2.7. Thành phần static

2.7.1. Ý nghĩa.

Trong một số trƣờng hợp, chúng ta cĩ nhu cầu sử dụng một biến là thành phần dữ liệu chung cho tất cả các đối tƣợng. Tuy nhiên, trong trƣờng hợp này, nếu sử dụng biến tồn cục cho cả chƣơng trình sẽ gây ra các nguy cơ nhất định và về mặt ngữ nghĩa sử dụng biến tồn cục cũng khơng hợp lý.

2.7.2. Dữ liệu static.

Để giải quyết vấn đề trên, ngơn ngữ C++ cho phép ngƣời lập trình sử dụng thành phần dữ liệu tĩnh (static data member). Thành phần dữ liệu tĩnh là thành phần chung của lớp đối tƣợng tƣơng ứng. Thành phần này khơng thuộc vào một đối tƣợng cụ thể nào cả mà nĩ là một thành phần chung cho tất cả các đối tƣợng của lớp tƣơng ứng.

Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 57 Cú pháp khai báo dữ liệu tĩnh:

static KiểuDữLiệu TênBiến;

ví dụ:

2.7.3. Hàm static.

Tƣơng tự, trong trƣờng hợp một số phƣơng thức của lớp khi sử dụng lại khơng cần một đối tƣợng cụ thể nào đĩ, chúng ta cũng cĩ thể khai báo chúng là các phƣơng thức tĩnh của lớp (static method).

Cú pháp khai báo phƣơng thức tĩnh:

static KDLTrảVề TênPhƣơngThức (DSThamSố);

Khi cài đặt, chúng ta khơng cần viết lại từ khĩa static

Ví dụ về quản lý các hĩa đơn bán hàng, mỗi hĩa đơn cĩ thuộc tính riêng là

tên hàng và số tiền. Vậy nếu quan tâm đến tổng số hĩa đơn đ đƣợc bán và tổng số tiền đ bán thì thơng tin này là dùng chung

Class A { private: static int t; int x; … public: … }; int A::t=1;

Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 58

3. HÀM FRIEND, LỚP FRIEND

3.1. Hàm friend

Thơng thƣờng thì một hàm khơng phải là thành phần của lớp thì nĩ khơng cĩ quyền truy cập đến những thành phần private, protected của đối tƣợng.

Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 59 Vậy để giải quyết vấn đề này thì chúng ta cĩ giải pháp là khai báo hàm thơng thƣờng này là bạn (friend) của lớp. Khi đĩ hàm này cĩ thể truy cập đƣợc những thuộc tính đã đĩng gĩi của lớp.

Cú pháp khai báo hàm bạn:

friend <khai báo hàm>;

khai báo này đƣợc đặt ở trong lớp, khi định nghĩa hàm này thì khơng cần đặt từ khĩa friend nữa.

ví dụ:

Lƣu ý: một hàm cĩ thể làm bạn của nhiều lớp. Khi đĩ phải khai báo mẫu trƣớc các tên lớp đĩ.

3.2. Lớp friend

Nếu lớp B đƣợc khai báo là bạn của lớp A thì tất cả các phƣơng thức của B cĩ thể truy xuất đến thành phần riêng của lớp A.

Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 60  Cĩ thể khai báo A là bạn của B và ngƣợc lại.

 Phải khai báo trƣớc các lớp. Cú pháp: friend class <Tênlớp>

Ví dụ:

4. ĐỊNH NGHĨA PHÉP TỐN

4.1. Ý nghĩa.

Trong phần trƣớc, chúng ta đã tìm hiểu các điều cơ bản của các lớp C++ và khái niệm kiểu dữ liệu trừu tƣợng. Các thao tác trên các đối tƣợng của lớp đƣợc thực hiện bằng cách gởi các thơng điệp (dƣới dạng các lời gọi hàm thành viên) tới các đối tƣợng. Cách gọi hàm này thì cồng kềnh cho các loại lớp nhất định, đặc biệt là các lớp tốn học. Trong mục này sẽ tìm hiểu làm thế nào cho phép các tốn tử của C++ làm việc với các đối tƣợng của lớp. Xử lý này đƣợc gọi là đa năng hĩa tốn tử (operator overloading) tức là chúng ta định nghĩa lại các hàm tốn tử để cĩ thể sử dụng cho các đối tƣợng.

Ví dụ: giả sử cĩ hai đối tƣợng x, y của lớp PhanSo. Muốn tính tổng của hai phân số này chúng ta khơng thể thực hiện phép tính x+y đƣợc vì tốn tử + khơng hỗ trợ cho kiểu dữ liệu do ngƣời dùng định nghĩa.

4.2. Nguyên tắc định nghĩa phép tốn.

 Mặc dù C++ khơng cho phép các tốn tử mới đƣợc tạo, nĩ cho phép các tốn tử đã tồn tại đƣợc đa năng hĩa sao cho khi các tốn tử này đƣợc sử dụng với các đối tƣợng của lớp. Đây chính là một đặc điểm mạnh của C++.

 Các tốn tử đƣợc đa năng hĩa bằng cách viết một định nghĩa hàm (bao gồm phần đầu và thân) nhƣ khi chúng ta viết một hàm bình thƣờng, ngoại trừ tên

Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 61 hàm bây giờ trở thành từ khĩa operator theo sau bởi ký hiệu của tốn tử đƣợc đa năng hĩa. Prototype của nĩ cĩ dạng nhƣ sau:

<KiểuDữLiệu> operator <Tốn tử> ( Danh sách tham số);

 Để sử dụng một tốn tử cho các đối tƣợng của lớp, tốn tử phải đƣợc đa năng hĩa ngoại trừ hai điều: Điều thứ nhất tốn tử gán cĩ thể sử dụng với mọi lớp mà khơng cần đa năng hĩa. Cách sử dụng mặc định của tốn tử gán là một phép gán thành viên của các thành viên dữ liệu của lớp. Chúng ta nhận thấy rằng sao chép thành viên mặc định thì nguy hiểm đối với các lớp với các thành viên mà đƣợc cấp phát động. Lúc đĩ chúng ta sẽ đa năng hĩa một cách tƣờng minh tốn tử gán đối với các lớp nhƣ thế. Điều thứ hai tốn tử địa chỉ (&) cũng cĩ thể đƣợc sử dụng với các đối tƣợng của bất kỳ lớp nào mà khơng cần đa năng hĩa; Nĩ trảvề địa chỉ của đối tƣợng trong bộ nhớ.

 Phần lớn các tốn tử trong C++ đều cĩ thể đƣợc đa năng hĩa. Bảng sau cho thấy các tốn tử cĩ thể đa năng hĩa:

+ - * / % ^ & |

~ ! = < > += -= *=

/= %= ^= &= |= << >> >>= <<= == != <= >= && || ++

-- ->* , -> || () new delete Và và bảng sau là các tốn tử khơng thể đa năng hĩa:

. .* :: ?: sizeof

 Thứ tự ƣu tiên của các tốn tử khơng đƣợc thay đổi.  Giữ đúng số ngơi của tốn tử đƣợc đa năng hĩa.

 Các hàm tốn tử cĩ thể khai báo là hàm thành viên của lớp (phƣơng thức của lớp, khi đĩ đối tƣợng bên trái của tốn tử phải là một đối tƣợng của lớp) hoặc cĩ thể khai báo là hàm thơng thƣờng, khi là hàm thơng thƣờng thì phải khai báo hàm bạn để cĩ thể truy cập đƣợc thành phần private và protected của lớp. Tuy nhiên cĩ những tốn tử chỉ cĩ thể là hàm bạn chẳng hạn nhƣ tốn tử >> và <<, vì để đa năng hĩa tốn tử << phải cĩ một tốn hạng trái của kiểu ostream & (nhƣ là cout trong biểu thức cout<<X. Tƣơng tự, đa năng hĩa tốn tử >> phải cĩ một tốn hạng trái của kiểu istream & (nhƣ là cin trong biểu thức cin>>X).

Lƣu ý: Để lựa chọn khi nào là hàm bạn khi nào là thành viên của lớp thì:

Nếu đối số đầu tiên của tốn tử là một đối tƣợng thì hàm tốn tử cĩ thể là hàm bạn hoặc là thành phần của lớp. Ngƣợc lại thì dùng hàm bạn

Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 62 4.2.1. Tốn tử nhập xuất dữ liệu >> và <<

Chúng ta cĩ thể đa năng hĩa các tốn tử chèn dịng << (stream insertion) và trích dịng >> (stream extraction). Hàm tốn tử của tốn tử << đƣợc đa năng hĩa cĩ prototype nhƣ sau:

ostream & operator << (ostream & stream, ClassName Object);

Hàm tốn tử << trả về tham chiếu chỉ đến dịng xuất ostream. Tham số thứ nhất của hàm tốn tử << là một tham chiếu chỉ đến dịng xuất ostream, tham số thứ hai là đối tƣợng đƣợc chèn vào dịng. Để bảo đảm cách dùng tốn tử << luơn nhất quán, chúng ta khơng thể định nghĩa hàm tốn tử << nhƣ là hàm thành viên của lớp đang xét, thơng thƣờng nĩ chính là hàm friend.

Cịn hàm tốn tử của tốn tử >> đƣợc đa năng hĩa cĩ prototype nhƣ sau:

istream & operator >> (istream & stream, ClassName Object);

Hàm tốn tử >> trả về tham chiếu chỉ đến dịng nhập istream. Tham số thứ nhất của hàm tốn tử này là một tham chiếu chỉ đến dịng nhập istream, tham số thứ hai là đối tƣợng của lớp đang xét mà chúng ta muốn tạo dựng nhờ vào dữ liệu lấy từ dịng nhập. Khi sử dụng, dịng nhập đĩng vai tốn hạng bên trái, đối tƣợng nhận dữ liệu đĩng vai tốn hạng bên phải. Cũng nhƣ trƣờng hợp tốn tử <<, hàm tốn tử >> khơng là hàm thành viên của lớp, thơng thƣờng nĩ chính là hàm friend.

Ví dụ:

Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 63

Minh họa việc khai báo và sử dụng tốn tử >>:

4.2.2. Phép tốn số học

 Định nghĩa phép tốn +, -, *, /

Cách 1: hàm tốn tử là thành viên của lớp

Ví dụ minh họa với lớp PhanSo

Sử dụng:

Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 64 kq= a + b; // kq =a. operator +(b)

Cách 2: hàm tốn tử là hàm bạn

Khai báo trong lớp PhanSo:

Định nghĩa:

Sử dụng:

4.2.3. Tốn tử quan hệ (>,<, >=, <=, ==)

Các tốn tử quan hệ thiết lập một quan hệ giữa các giá trị của tốn hạng. Chúng sinh ra một giá trị cĩ kiểu Boolean, là true nếu quan hệ đĩ là đúng và false nếu quan hệ đĩ là sai.

Ví dụ về tốn tử ==

Sử dụng:

Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 65 Sử dụng:

4.2.4. Phép gán.

Khi định nghĩa một lớp đối tƣợng mới, tƣơng tự nhƣ phƣơng thức khởi tạo sao chép mặc định, C++ tự động cung cấp cho lớp đối tƣợng này tốn tử gán mặc định. Tốn tử gán này cho phép thực hiện việc sao chép từng thành phần dữ liệu từ đối tƣợng nguồn sang đối tƣợng đích. Do vậy trƣờng hợp đối tƣợng cĩ chứa các thành phần dữ liệu là biến con trỏ, tốn tử gán mặc định đƣợc cung cấp bởi C++ chỉ sao chép phần địa chỉ (trong trƣờng hợp biến con trỏ) mà khơng thực hiện sao chép nội dung vùng nhớ mà đối tƣợng nguồn đang quản lý sang một vùng nhớ khác do đối tƣợng đích quản lý. Khi đĩ, cả 2 thành phần dữ liệu con trỏ của đối tƣợng nguồn và đối tƣợng đích sẽ cùng trỏ đến một vùng nhớ chung. Điều này khơng mong muốn của việc sao chép và cĩ thể dẫn đến các lỗi nghiêm trọng khi chạy chƣơng trình.

Từ lý do đĩ, đối với các lớp đối tƣợng mà cĩ thành phần dữ liệu là các biến con trỏ sử dụng cấp phát bộ nhớ động, ngƣời lập trình cần phải định nghĩa lại tốn tử gán để thực hiện quá trình sao chép phù hợp.

Cú pháp của tốn tử gán:

TenLopDT& operator=( TenLopDT&)

4.2.5. Phép tốn tăng, giảm. Tốn tử ++ (hoặc tốn tử --) cĩ 2 loại:  Tăng trƣớc: ++n:  Tăng sau: n++ Ví dụ:

Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 66 Lƣu ý: Tham số int ở dạng hậu tố chỉ mang ý nghĩa tƣợng trƣng (để phân biệt hàm với tiền tố) và dạng hậu tố cĩ thể khai báo là hàm thành viên của lớp

Hàm tốn tử dạng hậu tố ngồi là bạn của lớp nĩ cĩ thể là hàm thành phần của lớp

4.2.6. Phép tốn chuyển kiểu.

Với các kiểu dữ liệu chuẩn, chúng ta cĩ thể thực hiện các phép chuyển kiểu ngầm định, chẳng hạn cĩ thể gán một giá trị int vào một biến long, hoặc cộng giá trị

Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 67 long vào một biến float. Thƣờng cĩ hai kiểu chuyển kiểu: chuyển kiểu ngầm định (tự động) và chuyển kiểu tƣờng minh (ép kiểu). Phép chuyển kiểu ngầm định đƣợc thực hiện bởi chƣơng trình biên dịch. Phép chuyển kiểu tƣờng minh xảy ra khi sử dụng phép ép kiểu bắt buộc. Phép ép kiểu thƣờng đƣợc dung trong các câu lệnh gọi hàm để gửi các tham số cĩ kiểu khác với các tham số hình thức tƣơng ứng.

Các kiểu lớp khơng thể thoải mái chuyển sang các kiểu khác đƣợc mà phải do lập trình viên tự làm lấy. C++ cũng cung cấp cách thức định nghĩa phép chuyển kiểu ngầm định và tƣờng minh. Phép chuyển kiểu ngầm định đƣợc định nghĩa bằng một hàm thiết lập chuyển kiểu (conversion constructor), cịn phép chuyển kiểu tƣờng minh đƣợc xác định thơng qua tốn tử chuyển kiểu hoặc ép kiểu (cast operator).

Phép chuyển kiểu ngầm định đƣợc định nghĩa thơng qua một hàm thiết lập chuyển kiểu cho lớp. Với đối số cĩ kiểu cần phải chuyển thành một đối tƣợng của lớp. Tham số này cĩ thể cĩ kiểu cơ sở hay là một đối tƣợng thuộc lớp khác.

Ví dụ:

Sử dụng:

}

Các hàm thiết lập chuyển kiểu khơng thể sử dụng để chuyển các đối tƣợng của lớp mình sang các kiểu khác và chúng chỉ cĩ thể đƣợc sử dụng trong các phép gán và phép khởi tạo giá trị.

Tuy nhiên, các tốn tử chuyển kiểu cĩ thể đƣợc dùng để chuyển các đối tƣợng sang các kiểu khác và cũng cĩ thể đƣợc dùng cho các mục đích khác ngồi phép gán và khởi tạo giá trị. C++ qui định rằng một hàm tốn tử chuyển kiểu nhƣ thế buộc phải là hàm thành phần của lớp liên quan và khơng cĩ tham số hoặc kiểu trả về. Tên của nĩ đƣợc cho theo dạng nhƣ sau:

operator type();

trong đĩ type là tên của kiểu dữ liệu mà một đối tƣợng sẽ đƣợc chuyển sang; cĩ thể là kiểu dữ liệu cơ sở (khi đĩ ta phải chuyển kiểu từ đối tƣợng sang kiểu cơ sở) hay một kiểu lớp khác (khi đĩ ta phải chuyển kiểu từ đối tƣợng lớp này sang lớp khác).

Tài liệu giảng dạy Lập Trình Hƣớng Đối Tƣợng 68 Ví dụ:

Ghi nhớ:

- Tốn tử đƣợc định nghĩa chồng bằng cách định nghĩa một hàm tốn tử. Tên hàm tốn tử bao gồm từ khố operator theo sau là ký hiệu của tốn tử đƣợc

Một phần của tài liệu Lập trình hướng đối tượng (Trang 55 - 74)

Tải bản đầy đủ (PDF)

(111 trang)