Chương 4 - Overloading

You might also like

Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 49

CHƯƠNG 4: Nạp chồng toán tử

và hàm

Đậu Anh Tú _ Cpp


4.1 Giới thiệu

Đậu Anh Tú _ Cpp


4.1.Giới thiệu
 Nội dung trong chương này chúng ta sẽ xoay quanh class Complex{} gồm 2 thuộc tính
real, image là phần thực và phần ảo của 1 số ảo như sau:

Đậu Anh Tú _ Cpp


4.1.Giới thiệu
 Thực ra, vấn đề định nghĩa chồng toán tử đã từng có trong C, ví dụ trong biểu thức: a + b
ký hiệu + tuỳ theo kiểu của a và b có thể biểu thị:
o Phép cộng hai số nguyên
o Phép cộng hai số thực
o Phép cộng một số nguyên vào một con trỏ.
 Trong C++, có thể định nghĩa chồng đối với hầu hết các phép toán (một ngôi hoặc hai
ngôi) trên các class, nghĩa là một trong số các toán hạng tham gia phép toán là các
object. Đây là một khả năng mạnh vì nó cho phép xây dựng trên các class các toán tử cần
thiết, làm cho chương trình được viết ngắn gọn dễ đọc hơn và có ý nghĩa hơn.

Đậu Anh Tú _ Cpp


4.1.Giới thiệu
 Để có được điều trên, ta định nghĩa chồng các phép toán +, -, * và / bằng cách định nghĩa
hoạt động của từng phép toán giống như định nghĩa một hàm, chỉ khác là đây là hàm
toán tử (operator function).
 Hàm toán tử có tên được ghép bởi từ khoá operator và ký hiệu của phép toán tương ứng.
 Hàm toán tử có thể dùng như là một phương thức của một class hoặc là hàm tự do; khi
đó hàm toán tử phải được khai báo là friend của các class có các object mà hàm thao tác.

Đậu Anh Tú _ Cpp


4.2 Hàm toán tử

Đậu Anh Tú _ Cpp


4.2.1.Hàm toán tử là phương thức
 Ví dụ để xây dựng phương thức toán tử cộng giữa 2 đối tượng “+” cho class Complex{},
chúng ta sẽ sử dụng tham số ngầm định là đối tượng gọi hàm và truyền thêm 1 tham số
tường minh như sau:

 Chỉ thị c=a+b; trong ví dụ trên được chương trình dịch hiểu là c=a.operator+(b);

Đậu Anh Tú _ Cpp


4.2.1.Hàm toán tử là phương thức
 Thực ra cách viết a+b chỉ là một quy ước của chương trình dịch cho phép người sử dụng
viết gọn lại, nhờ đó cảm thấy tự nhiên hơn.
 Hàm toán tử operator+ phải có thuộc tính public vì nếu không chương trình dịch không
thể thực hiện được nó ở ngoài phạm vi lớp.
 Trong lời gọi a.operator+(b), a đóng vai trò của tham số ngầm định của phương thức và
b là tham số tường minh. Số tham số tường minh cho hàm toán tử thành phần luôn ít hơn
số ngôi của phép toán là 1 vì có một tham số ngầm định là đối tượng gọi hàm toán tử.
 Chương trình dịch sẽ không thể hiểu được biểu thức 3+a vì cách viết tương ứng
3.operator+(a) không có ý nghĩa. Để giải quyết tình huống này ta dùng hàm friend để
định nghĩa hàm toán tử.

Đậu Anh Tú _ Cpp


4.2.2.Hàm toán tử là hàm bạn
 Bằng cách thêm hàm toán tử cộng thêm một số thực float vào phần thực của một đối
tượng Complex, được biểu thị bởi phép cộng với số thực float là toán hạng thứ nhất, còn
đối tượng Complex là toán hạng thứ hai. Trong trường hợp này không thể dùng phép
cộng như phương thức vì tham số thứ nhất của hàm toán tử không còn là một đối tượng.

Đậu Anh Tú _ Cpp


4.2.2.Hàm toán tử là hàm bạn
 Trong chương trình trên, biểu thức a+b được chương trình hiểu là lời gọi phương thức
a.operator+(b), trong khi đó với biểu thức 3+a, chương trình dịch sẽ thực hiện lời gọi
hàm tự do operator+(3,a).
 Số tham số trong hàm toán tử tự do operator+(...) đúng bằng số ngôi của phép + mà nó
định nghĩa. Trong định nghĩa của hàm toán tử tự do, tham số thứ nhất có thể có kiểu bất
kỳ chứ không nhất thiết phải có kiểu class nào đó.
 Với một hàm operator+ nào đó chỉ có thể thực hiện được phép + tương ứng giữa hai toán
hạng có kiểu như đã được mô tả trong tham số hình thức, nghĩa là muốn có được phép
cộng “vạn năng” áp dụng cho mọi kiểu toán hạng ta phải định nghĩa rất nhiều hàm toán
tử operator+ (định nghĩa chồng các hàm toán tử).

Đậu Anh Tú _ Cpp


4.2.2.Hàm toán tử là hàm bạn
 Vấn đề bảo toàn các tính chất tự nhiên của các phép toán không được C++ đề cập, mà
nó phụ thuộc vào cách cài đặt cụ thể trong chương trình dịch C++ hoặc bản thân người
sử dụng khi định nghĩa các hàm toán tử. Chẳng hạn, phép gán c=a+b; được hiểu như là
c=a.operator+(b);
 Trong khi đó với phép gán d=a+b+c, ngôn ngữ C++ không đưa ra diễn giải nghĩa duy
nhất. Theo thứ tự ưu tiên trong các phép toán thì cách cài đặt ban đầu chương trình biên
dịch sẽ tạo ra đối tượng trung gian t: t=a.operator+(b); và d=t.operator+(c);
 Cũng có thể làm như sau: trong định nghĩa của hàm toán tử, ta trả về tham chiếu đến
một trong hai tượng tham gia biểu thức (chẳng hạn a). Khi đó a+b+c được hiểu là
a.operator+(b) và sau đó là a.operator+(c) bằng cách cài đặt như sau:

Đậu Anh Tú _ Cpp


4.2.2.Hàm toán tử là hàm bạn
 Trong hai ví dụ trên, việc truyền các đối số và giá trị trả về của hàm toán tử được thực
hiện bằng tham trị. Với các đối tượng có kích thước lớn, người ta thường dùng tham
chiếu để truyền đối số cho hàm. Ví dụ:

 Hàm toán tử cũng có thể trả về kiểu void khi ảnh hưởng chỉ tác động lên một trong các
toán hạng tham gia biểu thức. Ví dụ phương thức đảo dấu số phức sau:

 Với cách cài đặt như trên, khi thực hiện phép tính c = - a + b; sẽ gây lỗi vì –a có kiểu trả
về là void, ta chỉ nên sử dụng –a; đứng riêng lẻ.
Đậu Anh Tú _ Cpp
4.3 Khả năng và giới hạn của overload

Đậu Anh Tú _ Cpp


4.3.Khả năng và giới hạn của định nghĩa chồng toán tử

 Ký hiệu đứng sau từ khoá operator phải là một trong số các ký hiệu toán tử áp dụng cho
các kiểu dữ liệu cơ sở, không thể dùng các ký hiệu mới. Các toán tử không thể định
nghĩa chồng :
o Toán tử truy nhập thành phần “.” (chấm)
o Toán tử định phạm vi “::”
o Toán tử ba ngôi “?:”
o Toán tử lấy kích thước “sizeof()”

Đậu Anh Tú _ Cpp


4.3.Khả năng và giới hạn của định nghĩa chồng toán tử

 Một số toán tử ta phải tuân theo các ràng buộc sau:


• Phép =, [] nhất định phải được định nghĩa như phương thức của lớp.
• Phép << và >> dùng với cout và cin phải được định nghĩa như hàm bạn.
• Hai phép toán ++ và -- có thể sử dụng theo hai cách khác nhau ứng với dạng tiền tố ++a, --b
và dạng hậu tố a++, b--. Điều này đòi hỏi hai hàm toán tử khác nhau.
 Khi nạp chồng, các toán tử có thể định nghĩa khác cách hiểu thông thường nhưng phải
bảo toàn số ngôi vốn có. Ví dụ phép trừ “-” có thể định nghĩa 1 ngôi (phép đảo dấu) hoặc
2 ngôi (phép trừ số học) hay định nghĩa để có tác dụng như phép cộng nhưng phép tăng
“++” vốn chỉ một ngôi thì chúng ta không thể định nghĩa nó thành 2 ngôi, trình biên dịch
sẽ hiểu ta đang tạo ra phép toán mới.

Đậu Anh Tú _ Cpp


4.3.Khả năng và giới hạn của định nghĩa chồng toán tử

 Khi định nghĩa chồng toán tử, phải tuân theo nguyên tắc là Một trong số các toán hạng
phải là đối tượng. Nói cách khác, hàm toán tử phải:
o Đối với toán tử có tham số đầu tiên là đối tượng, ta thường định nghĩa nó như là phương thức
của class.
o Đối với toán tử có các tham số khác nhau về kiểu dữ liệu, ta định nghĩa thông qua hàm friend
Hơn nữa, mỗi hàm toán tử chỉ có thể áp dụng với kiểu toán hạng nhất định; cần chú ý rằng các
tính chất vốn có, chẳng hạn tính giao hoán của toán tử không thể áp dụng một cách tuỳ tiện cho
các toán tử được định nghĩa chồng.

Đậu Anh Tú _ Cpp


4.4 Chiến lược sử dụng overload

Đậu Anh Tú _ Cpp


4.4.Chiến lược sử dụng hàm toán tử
 Về nguyên tắc, định nghĩa chồng một phép toán là khá đơn giản, nhưng việc sử dụng phép toán
định nghĩa chồng lại không phải dễ dàng và đòi hỏi phải cân nhắc vì nếu bị lạm dụng sẽ làm cho
chương trình khó hiểu.
 Phải làm sao để các phép toán vẫn giữ được ý nghĩa trực quan nguyên thuỷ của chúng. Chẳng
hạn không thể định nghĩa cộng “+” như phép trừ “-” hai giá trị. Phải xác định trước ý nghĩa các
phép toán trước khi viết định nghĩa của các hàm toán tử tương ứng.
 Lưu ý: không nên định nghĩa những hàm hàm toán tử khác nhau cùng làm những công việc
giống nhau vì dễ xảy ra nhập nhằng. Ví dụ: đã có một hàm operator+ là một phương thức có
tham số là đối tượng Complex thì không được định nghĩa thêm một hàm operator+ là một hàm
tự do có hai tham số là đối tượng Complex.

Đậu Anh Tú _ Cpp


4.4.Chiến lược sử dụng hàm toán tử
 Các toán tử gán: =, +=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=
o Do các toán tử gán được định nghĩa dưới dạng phương thức, nên chỉ có một tham số tường minh và
không có ràng buộc gì về kiểu đối số và kiểu giá trị trả về của các phép gán.
 Toán tử truy nhập thành phần ->
o Phép toán này được dùng để truy xuất các thành phần của một cấu trúc hay một lớp và cần phân biệt với
những cách sử dụng khác để tránh dẫn đến sự nhầm lẫn. Có thể định nghĩa phép toán lấy thành phần
giống như đối với các phép toán một ngôi.
 Toán tử truy nhập thành phần theo chỉ số []
o Toán tử lấy thành phần theo chỉ số được dùng để xác định một thành phần cụ thể trong một khối dữ liệu
( cấp phát động hay tĩnh ). Thông thường phép toán này được dùng với mảng, nhưng cũng có thể định
nghĩa lại nó khi làm việc với các kiểu dữ liệu khác. Chẳng hạn với kiểu dữ liệu vector có thể định nghĩa
phép lấy theo chỉ số để trả về một thành phần toạ độ nào đó vector. Và phải được định nghĩa như
phương thức có một đối số tường minh.

Đậu Anh Tú _ Cpp


4.5 Định nghĩa 1 số phép toán

Đậu Anh Tú _ Cpp


4.5.1.Định nghĩa cho phép tăng, giảm
 Trường hợp các toán tử ++ và --:

 Chú ý kiểu tham số int là tham số giả định để xác định dạng tiền tố hay hậu tố, khi thực
hiện phép toán thực tế không cần phải truyền tham số.
 Chỉ sử dụng trả về tham chiếu với dạng tiền tố, còn đối với dạng hậu tố, khi định nghĩa
cần thực hiện tạo 1 biến tạm để nhận giá trị trước khi tăng, sau đấy tăng this lên và trả về
biến tạm.

Đậu Anh Tú _ Cpp


4.5.2.Định nghĩa chồng phép gán
 Tương tự copy constructor, việc định nghĩa phép gán bằng “=” chỉ cần khi có thành phần
thuộc tính của class được cấp phát động.
 Điểm khác nhau giữa copy constructor và phép gán bằng “=” là copy constructor được
dùng để khởi tạo giá trị 1 đối tượng dựa trên 1 đối tượng khác, còn phép gán bằng “=”
được dùng để gán giá trị cho 1 đối tượng có sẵn.
 Hàm gán nhất thiết phải được định nghĩa như là phương thức của class.
 Xét a và b là 2 object, trong hàm gán nói chung và gán bằng nói riêng, ví dụ: a = b; được
hiểu là a.operator=(b); do đó b được truyền cho hàm dưới dạng tham trị hoặc tham
chiếu.
 Việc truyền bằng tham trị đòi hỏi sự có mặt của copy constructor (truyền tham trị thì ta
cần copy object vào 1 đối tượng tạm), hơn thế nữa sẽ làm cho chương trình chạy chậm vì
mất thời gian sao chép một lượng lớn dữ liệu. Vì vậy, b sẽ được truyền cho hàm gán dưới
dạng tham chiếu. Đậu Anh Tú _ Cpp
4.5.2.Định nghĩa chồng phép gán
 Giá trị trả về của hàm gán phụ thuộc vào mục đích sử dụng của biểu thức gán. Chúng ta
chọn giải pháp trả về tham chiếu của đối tượng đứng bên trái dấu bằng nhằm giữ hai tính
chất quan trong của biểu thức gán:
o Trật tự kết hợp từ bên phải sang trái
o Có thể sử dụng kết quả biểu thức gán trong các biểu thức khác. Ngoài ra giải pháp này cũng
hạn chế việc sao chép dữ liệu từ nơi này đi nơi khác trong bộ nhớ.
 Chúng ta phân biệt hai trường hợp:
o a=a; với hai toán hạng là một. Trường hợp này hàm operator= không làm gì, ngoài việc trả
về tham chiếu đến a.
o a=b; khi hai đối tượng tham gia biểu thức gán hoàn toàn khác nhau, việc đầu tiên là phải giải
phóng vùng nhớ động trước đó trong a, sau đấy cấp phát một vùng nhớ động khác bằng kích
thước vùng nhớ động có trong b, sao chép nội dung từ vùng nhớ động trong b sang a. Và cuối
cùng sao chép giá trị của các thành phần “không động” còn lại. Việc giải phóng vùng nhớ
trong a rồi cấp phát lại thường được sử dụng khi gán mảng, vector… Đậu Anh Tú _ Cpp
4.5.2.Định nghĩa chồng phép gán
 Xét class Vector{} gồm 2 thuộc tính n là số lượng toạ độ của Vector, v là con trỏ trỏ tới vùng nhớ
chứa các toạ độ đấy, khi đấy ta thiết lập hàm gán bằng “=” như sau:

Đậu Anh Tú _ Cpp


4.5.3.Định nghĩa chồng phép []
 Với lớp class ở trên, ta có cách nạp chồng phép [] như sau:

 Nhờ giá trị trả về của hàm operator[] là tham chiếu đến một thành phần toạ độ của vùng nhớ
động nên ta có thể đọc/ghi các thành phần toạ độ của mỗi đối tượng Vector. Như vậy có thể sử
dụng các đối tượng Vector giống như các biến mảng.
 Có thể cải tiến hàm toán tử operator[] bằng cách bổ sung thêm phần kiểm tra tràn chỉ số hoặc chỉ
số âm.

Đậu Anh Tú _ Cpp


4.5.4.Định nghĩa << và >>
 Có thể định nghĩa chồng hai toán tử vào/ra << và >> cho phép các đối tượng đứng bên phải
chúng khi thực hiện các thao tác vào ra. Quay lại với class Complex{}, ta có thể định nghĩa >> và
<< như sau:

Đậu Anh Tú _ Cpp


4.5.4.Định nghĩa << và >>
 Trong chương trình trên, ta không thấy các phương thức khởi tạo tường minh để gán giá trị cho
các đối tượng. Thực tế, việc gán các giá trị cho các đối tượng được đảm nhiệm bởi hàm toán tử
operator>>.
 Việc hiển thị nội dung của các đối tượng số phức có trước đây do phương thức display() đảm
nhiệm hay việc gán giá trị cũng có thể cài đặt phương thức set() để gán giá trị cho đối tượng thì
nay đã có thể thay thế nhờ hàm toán tử operator<< và operator>> nhưng chúng ta sẽ không
khuyến khích việc sử dụng như thế vì sẽ vi phạm tính đóng gói của class.

Đậu Anh Tú _ Cpp


4.5.5.Định nghĩa chồng các toán tử new và delete
 Thông thường chúng ta thường khi ít quan tâm đến việc nạp chồng các toán tử new, delete. Trong
một số trường hợp cần cài đặt thêm 1 số chức năng (thông báo cấp phát, thông báo thu hồi, gán
con trỏ về null…), chúng ta có thể nạp chồng 2 toán tử này.
 Chúng ta có thể nạp chồng toán tử new và delete theo 2 cách:
o Nạp chồng cục bộ phạm vi class, lúc này ta nạp chồng new với delete theo tư cách là phương thức của
class, khi sử dụng, trình biên dịch sẽ kiểm tra class có được nạp chồng riêng new và delete hay không,
nếu có thì sẽ sử dụng phương thức đấy còn ngược lại sẽ sử dụng new và delete toàn cục.
o Nạp chồng toàn cục, lúc này new và delete thay thế cái mặc định của C++ và áp dụng cho mọi kiểu dữ
liệu

Đậu Anh Tú _ Cpp


4.5.5.Định nghĩa chồng các toán tử new và delete
 Khi nạp chồng new, chúng ta phải tuân theo 1 số quy tắc sau:
o Kiểu trả về là void * (con trỏ kiểu void)
o Có 1 tham số size_t tương ứng với 1 kích thước cụ thể (đây là tham số giả vì thực tế khi sử dụng new, chúng ta không
cần phải truyền tham số này vào mà chương trình sẽ tự động tính kích thước cần cấp phát cho chúng ta.)
o Chúng ta thường sử dụng hàm malloc() để xin cấp phát bộ nhớ trong khi định nghĩa new

Ví dụ :

Đậu Anh Tú _ Cpp


4.5.5.Định nghĩa chồng các toán tử new và delete
 Khi nạp chồng delete, chúng ta phải tuân theo 1 số quy tắc sau:
o Kiểu trả về là void
o Có 1 tham số con trỏ kiểu void tương ứng lưu địa chỉ của vùng nhớ cần giải phóng.
o Chúng ta thường sử dụng hàm free() để giải phóng bộ nhớ trong khi định nghĩa delete (sử dụng delete cho con trỏ
kiểu void gây lỗi “deleting 'void*' is undefined” )
Ví dụ:

Đậu Anh Tú _ Cpp


4.5.5.Định nghĩa chồng các toán tử new và delete
 Ví dụ nạp chồng new và delete cho class Complex{}

Đậu Anh Tú _ Cpp


4.5.5.Định nghĩa chồng các toán tử new và delete

 Nhận xét:
 Khi đã nạp chồng new, delete cục bộ, ta vẫn có thể gọi được các toán tử new và delete
toàn cục thông qua toán tử phạm vi.
 Các toán tử new và delete là các phương thức static của các lớp bởi vì chúng không có
tham số ngầm định.

Đậu Anh Tú _ Cpp


Bài tập vận dụng

Đậu Anh Tú _ Cpp


Phép nhân ma trận véc tơ

 Bài tập, xây dựng 2 class Matrix{}, và class Vector{} như sau:

 Trong đấy class Matrix{} chứa 2 biến n,m lần lượt là 2 chiều của ma trận, con trỏ cấp 2 **v
dùng để quản lý các phần tử của ma trận.
 Trong đấy class Vector{} chứa biến n là độ dài Vector , con trỏ *v dùng để quản lý các phần tử
của Vector.
 Xây dựng các phương thức khởi tạo, phương thức huỷ, nạp chồng toán tử nhập, xuất, và phép
Đậu Anh Tú _ Cpp
nhân giữa Matrix và Vector.
Phép nhân ma trận véc tơ

 Hướng dẫn nhân 2 ma trận với nhau:

Đậu Anh Tú _ Cpp


4.6 Chuyển đổi kiểu dữ liệu

Đậu Anh Tú _ Cpp


4.6.1.Chuyển đổi kiểu dữ liệu
 C++ cho phép chúng ta chuyển đổi kiểu dữ liệ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 dùng 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.
 Khi tính toán biểu thức, trình biên dịch sẽ tách mỗi biểu thức thành những biểu thức con
nhỏ hơn. Các toán tử số học đòi hỏi các toán hạng phải cùng kiểu dữ liệu.
 Để đảm bảo điều này, trình biên dịch sử dụng các quy tắc ép kiểu ngầm định sau đây:
 Nếu toán hạng là một số nguyên có miền giá trị nhỏ hơn kiểu int (bool, char, unsigned char,
signed char, unsigned short, signed short), toán hạng đó sẽ tự động chuyển về kiểu int hoặc
unsigned int.
 Nếu vẫn không phù hợp, trình biên dịch (compiler) sẽ chuyển các toán hạng về cùng kiểu dữ
liệu với toán hạng có độ ưu tiên cao nhất.

Đậu Anh Tú _ Cpp


4.6.1.Chuyển đổi kiểu dữ liệu

 Độ ưu tiên kiểu dữ liệu của các toán hạng như sau:

 Việc chuyển đổi từ kiểu dữ liệu lớn sang kiểu dữ liệu bé hơn sẽ gây ra 1 số kết quả không
mong muốn (tràn số, mất 1 phần giá trị …)

Đậu Anh Tú _ Cpp


4.6.1.Chuyển đổi kiểu dữ liệu

 Các kiểu class 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ự định nghĩa. Có khá nhiều trường hợp class cần phải ép kiểu (gán đối tượng bằng
1 kiểu dữ liệu khác, ép đối tượng sang 1 kiểu dữ liệu khác, chuyển kiểu trong biểu thức
….)
 Tuỳ theo từng trường hợp, ta sẽ xây dựng các cách thức ép kiểu khác nhau: phương thức
khởi tạo (constructor), nạp chồng phép gán, nạp chồng phép ép kiểu hoặc xây dựng
phương thức, hàm tự do cụ thể cho việc ép kiểu.

Đậu Anh Tú _ Cpp


4.6.2.Chuyển đổi kiểu dữ liệu bằng phép ép kiểu
 Phép ép kiểu được sử dụng khi cần chuyển 1 đối tượng của class sang 1 kiểu dữ liệu
khác
 Phép ép kiểu phải là phương thức của lớp, không phải là phương thức tĩnh hay hàm
friend.
 Cú pháp của phép ép kiểu:
 Ví dụ Ép kiểu Complex sang số thực:

Đậu Anh Tú _ Cpp


4.6.3.Chuyển đổi kiểu dữ liệu bằng Constructor
 Chuyển đổi kiểu dữ liệu bằng Constructor khi cần phải chuyển đổi 1 kiểu dữ liệu sang
đối tượng của class
 Chúng ta xây dựng Constructor với 1 tham số là kiểu dữ liệu cần chuyển đổi
 Ví dụ Ép kiểu số thực sang đối tượng Complex:

 Chú ý nếu chúng ta sử dụng constructor khởi tạo có truyền tham số mặc định thì có thể
sẽ gây ra lỗi “ambiguous”
Đậu Anh Tú _ Cpp
4.6.3.Chuyển đổi kiểu dữ liệu bằng Constructor
 Chú ý, không xây dựng cả 2 phép chuyển đổi kiểu dữ liệu vì sẽ gây ra lỗi “ambiguous”
trong biểu thức (biểu thức chứa cả 2 toán hạng có 2 kiểu dữ liệu thì sẽ không xác định
được nên ưu tiên ép sang kiểu dữ liệu nào).

 Ví dụ xét 2 biến : Ta thấy khi thức hiện biểu thức x + a,


compiler cần phải xác định nên ép x sang Complex hay là nên chuyển a sang float để
thực hiện. Việc định nghĩa cả 2 cách ép kiểu sẽ gây sự chồng chéo nói trên.
 Nếu vẫn muốn sử dụng cả 2 phép chuyển đổi nói trên, trong biểu thức khi cần phải ép
kiểu, ta sẽ gọi cụ thể cách ép kiểu tương ứng. Ví dụ x + float (a) hoặc Complex(x) + a.

Đậu Anh Tú _ Cpp


4.6.4.Chuyển đổi kiểu dữ liệu bằng hàm tự do
 Chúng ta có thể định hàm tự do để chuyển đổi kiểu dữ liệu. Sử dụng tính chất của nạp
chồng hàm mà chúng ta có thể định nghĩa nhiều kiểu chuyển đổi chỉ cùng với 1 tên duy
nhất.
 Ví dụ:

Đậu Anh Tú _ Cpp


4.7 Tham số và kiểu trả về

Đậu Anh Tú _ Cpp


4.7.Tham số và kiểu trả về
 Khi overload một toán tử hay hàm, ta có nhiều sự lựa chọn về việc truyền tham số và
kiểu trả về.
 Đối với các đối tượng nhất là các đối tượng lớn, chúng ta nên lựa chọn truyền tham
chiếu mỗi khi có thể.
 Nếu trong trường hợp không muốn đối số bị sửa đổi, ta sử dụng hằng tham chiếu (hầu
hết các toán tử so sánh, logic không sửa đổi các toán hạng, copy constructor… chúng ta
sẽ rất hay dùng đến hằng tham chiếu).
 Ví dụ:

Đậu Anh Tú _ Cpp


4.7.Tham số và kiểu trả về
 Không có giới hạn cho kiểu trả về trong khi overload toán tử nhưng nên cố gắng tuân
theo tinh thần cài đặt có sẵn của các toán tử.
 Các phép toán một ngôi nên sử dụng trả về tham chiếu đến đối tượng ban đầu. Ví dụ:

 Các phép toán sinh ra một giá trị mới nên trả về một giá trị (thay vì tham chiếu) và nên
để kiểu const (để kết quả ấy không thể bị sửa đổi). Ví dụ:

Đậu Anh Tú _ Cpp


4.7.Tham số và kiểu trả về
 Trong khi xây dựng hàm trong C++, chúng ta thường tạo 1 đối tượng chỉ có chức năng nhận giá
trị trả về và return chúng. Tuy việc làm này là không tối ưu ví dụ:

 Trong cách dùng trên, đầu tiên chúng ta gọi Constructor khởi tạo để tạo đối tượng c (dòng 2),
sau đấy gọi copy constructor để tạo bản sao cho giá trị trả về của hàm (dòng 5), và gọi
destructor để huỷ đối tượng c khi ra khỏi hàm.

Đậu Anh Tú _ Cpp


4.7.Tham số và kiểu trả về
 C++ cho chúng ta một cách trả về thuận tiện hơn bằng cách tạo 1 đối tượng tạm
thời (temporary object) trong chính câu lệnh trả về.

 Khi trình biên dịch gặp đoạn mã này, nó hiểu đối tượng được tạo chỉ nhằm mục
đích làm giá trị trả về, nên nó tạo thẳng một đối tượng bên ngoài (để trả về) - bỏ
qua việc tạo và huỷ đối tượng bên trong lời gọi hàm. Và chỉ có một lời gọi duy
nhất đến constructor của Complex (không phải copy constructor) thay vì dãy lời
gọi trước.
 Đây là quá trình tối ưu hoá giá trị trả về

Đậu Anh Tú _ Cpp


4.7.Tham số và kiểu trả về
 Ví dụ về 1 số hàm phía trên được tối ưu hoá giá trị trả về:

Đậu Anh Tú _ Cpp

You might also like