You are on page 1of 24

Hàm nạp chồng/quá tải

Overloaded functions

Ts. Trần Thanh Hải


Mở đầu

• Ví dụ 1: in ra màn hình số int, float, double, char


cout<<"So nguyen int: "<<10<<endl;
cout<<"So float: "<<10.5<<endl;
cout<<"So double: "<<11.25<<endl;
cout<<"Ky tu char "<<'c'<<"\t"<<int('c')<<endl;

• Ví dụ 2: tính giá trị tuyệt đối của biến sử dụng hàm abs();
#include<cmath>
cout<<"Gia tri tuyet doi cua so nguyen int "<<abs(-10)<<endl;
cout<<"Gia tri tuyet doi cua so thuc float "<<abs(-10.3)<<endl;
Mở đầu

• Ví dụ 3: Xét danh sách phòng thi, thí sinh trùng tên nhau thì
phải so sánh với trường khác để phân biệt

Họ và tên Ngày tháng năm Nơi sinh Nam/Nữ


Nguyễn A 20/5/1998 Nghệ an Nam
Nguyễn A 20/5/1998 Hà Nội Nam
Nguyễn B 15/9/2005 Hà Nội Nam
Phạm Hương 10/6/1999 Phú thọ Nữ
Phạm Minh Anh 27/11/1999 Quảng Ninh Nữ
Mở đầu

• Phân loại: Nạp chồng hàm – toán tử


• Toán tử có thể nạp chồng (Xét sau)
+ - * / % ^
& | ~ ! , =
< > <= >= ++ --
<< >> == != && ||
+= -= /= %= ^= &=
|= *= <<= >>= [] ()
-> ->* new new [] delete delete []
• Toán tử không thể nạp chồng
:: .* . ?:
• Ví dụ: https://www.tutorialspoint.com/cplusplus/cpp_overloading.htm
Hàm nạp chồng

• Chữ ký của hàm: (nguyên tắc lập hàm)


+ Tên hàm và danh sách tham số.
+ Phải duy nhất cho mỗi định nghĩa hàm.
• Hai hàm khác nhau: có thể có cùng tên nếu:
+ Các tham số của chúng là khác nhau.
+ Hoặc là chúng có số tham số khác nhau.
+ Hoặc bất kỳ các tham số của chúng là có một kiểu khác.
+ (hai định nghĩa riêng biệt)
• Chú ý: một hàm không thể được nạp chồng chỉ bằng kiểu nó
trả về. Ít nhất một trong các tham số của nó phải khác kiểu
Ví dụ 1: in ra màn hình: số nguyên, double, char

void print(int i) {
cout << "\tIn so nguyen (int): " << i << endl;
}
void print(double f) {
cout << "\tIn so thuc (float): " << f << endl;
}
void print(char* c) {
cout << "\tIn xau ky tu (character): " << c << endl;
}
Nhập xâu ký tự
• string str;
• char ch[80];
Ví dụ 2: Hàm trị tuyệt đối của số int và float

int absolute(int var) {


if (var < 0)
var = -var;
return var;
}

float absolute(float var) {


if (var < 0)
var = -var;
return var;
}
Ví dụ 3: hàm thao tác với hai số

// overloading functions
int operate (int a, int b) // int operate (int a, double b)
{ return (a*b); }
double operate (double a, double b)
{ return (a/b); }
int main () {
int x = 5,y = 2;
double n = 5.0, m = 2.0;
cout << operate (x,y) << '\n';
cout << operate (n,m) << '\n';
return 0; }
Ví dụ 4. Nạp chồng và các tham số mặc định

#include <iostream>
using namespace std;
int fun(int = 0, int = 0);
int main(){
cout<< fun();
cout<< fun(5);
cout<< fun(3,5);
}
int fun(int x, int y) {
return (x + y);
}
Vấn đề tiếp

• Nạp chồng hàm cũng có thể có cùng nội dung


• Ví dụ : nạp chồng hàm có kiểu khác nhau – cùng nội dung
int sum (int a, int b) {
return a + b;
}
double sum (double a, double b) {
return a + b;
}
int main () {
cout << sum (10,20) << '\n'; // goi hàm int sum
cout << sum (1.0,1.5) << '\n‘; // gọi ham double sum
}
Giá trị cùng tên (2 phạm vi khác nhau - toàn cục và
địa phương) làm thế nào để phân biệt?

#include<iostream>
using namespace std;

int X =10; // bien toan cuc


int main()
{
int X =7; // bien cuc bo

cout<<"Gia tri cua bien cuc bo X = "<<X<<endl;


cout<<"Gia tri cua bien toan cuc X = "<<::X<<endl;
cout<< "Gia tri cua bien toan cuc (nhan)X 2 = "<<::X*2<<"\n";

return 0;
}
Hàm giống nhau

• Vì nhiều người tham gia viết chương trình do đó có khả năng


hàm giống nhau (trùng nhau) cả về tên và đối và có thể giống
hàm có sẵn trong máy? Do đó complier không biết bản nào.
• Sử dụng namespace: using namespace std;
• Cú pháp: namespace ten_cua_namespace {
// khai báo code
}
• Vị trí khai báo: ngoài hàm main().
• Để gọi phiên bản namespace của hàm hoặc biến như sau:
ten_cua_namespace::code
• Giống như ta quen với cách gọi đối với cout, cin, endl như sau:
std:: cout<<“Hello nhom tin hoc \n”;
Ví dụ 1
#include<iostream>
using namespace std;
// Dinh nghia namespace
namespace dau_tien {
void ham() {
cout<<"Ben trong namespace dau tien \n";
}
}
namespace thu_hai{
void ham() {
cout<<"Ben trong namespace thu hai \n";
}
}
using namespace dau_tien;
int main() {
ham(); // Cách 1 goi ham trong namespace 1
thu_hai::ham(); // Cach 2
}
Namespace có thể lồng nhau

• Cú pháp
namespace ten_thu_nhat{
// Phần khai báo các code
namespace ten_thu_hai{
// Phần khai báo các code
}
}
• Truy cập vào thành viên đầu tiên: using namespace ten_thu_nhat;
• Truy cập thành viên thứ 2:
• using namespace ten_thu_nhat::ten_ thu_hai;
Hàm mẫu

• Đối với các trường hợp này, C ++ có khả năng định nghĩa
các hàm với các kiểu generic, gọi là các mẫu hàm.
• Định nghĩa một mẫu hàm theo cú pháp giống như một
hàm thông thường, ngoại trừ nó được đặt trước bởi từ
khóa template và một loạt các tham số mẫu kèm theo
khung góc <>:
• template <template-parameters> function-declaration
• Ví dụ
template <class SomeType>
SomeType sum (SomeType a, SomeType b){ // int sum(int a, int b)
return a+b;
}
Được gọi trong hàm main(): x = sum<int>(10,20);
template <class T>
T sum (T a, T b) {
T result; // biến trung gian
result = a + b;
return result;
}
int main () {
int i = 5, j = 6, k;
double f = 2.0, g = 0.5, h;
k = sum<int>(i,j);
h = sum<double>(f,g);
cout << k << '\n';
cout << h << '\n';
return 0;
}
Ví dụ 2

#include <iostream>
using namespace std;
template <class T, class U>
bool are_equal (T a, U b) {
return (a==b);
}
int main () {
if (are_equal(10,10.0)) // are_equal<int, float>(10,10.0)
cout << "x and y are equal\n";
else cout << "x and y are not equal\n"; return 0;
} OUTPUT: x and y are equal
Ví dụ 3: Các đối số mẫu không phải là kiểu (tức là hàm nhân với
một số nào đó)
template <class T, int N>
T fixed_multiply (T val) {
return val * N; }
int main() {
cout << fixed_multiply<int,2>(10) << '\n';
} OUTPUT: 20
template <class T> // so sánh 2 cách thiết lập template
T fixed_multiply (T val, int N) {
return val * N;
}
int main() {
cout << fixed_multiply<int>(10,2) << '\n'; // có thể gọi theo cách 1
cout << fixed_multiply(10,2) << '\n'; // có thể gọi theo cách 2
}
// Còn như <class T, int N> thì chỉ có 1 cách gọi duy nhất
Trao đổi - Mở rộng

#include<iostream>
using namespace std;
template <class T> // 1. Vị trí template - phía trên main().
T sum_ab(T a, T b) {
return (a+b);
}
int main() {
int a = 5, b = 10;
int c1, c2;
c1 = sum_ab(a,b); //2. cách 1 gọi hàm
cout<<"Gia tri cua tong (a+b) = "<<c1<<endl;
c2 = sum_ab<int>(a,b); // cách 2 gọi hàm
cout<<"Gia tri cua tong (a+b) = "<<c2<<endl;
} tv1.cpp
Ví dụ in các phần tử của mảng

#include<iostream> // In phần tử mảng với các kiểu khác nhau


template<class type>
void printArray(const type *arr, const int N){
for(int i = 0; i<N; i++){
cout<<"arr["<<i<<"]= "<<arr[i]<<endl;
}
}
int main(){
int a[]={1, 2, 3, 4, 5};
float b[] = {1.2, 3.5, 10.8};
char str[] = {'t', 'e','m','p','l','a','t','e'};
printArray(a,5);
cout<<"In mang 1 chieu so thuc \n";
printArray(b,3);
cout<<"in mang ky tu \n";
printArray(str,8);
} tv2_array.cpp
Template và tham số không kiểu (sử dụng cách 2)
#include<iostream>
using namespace std;
template<class type, int N>
void printArray(const type *arr) {
for(int i = 0; i<N; i++){
cout<<"arr["<<i<<"]= "<<arr[i]<<endl;
}
}
int main(){
int a[]={1, 2, 3, 4, 5};
float b[] = {1.2, 3.5, 10.8};
char str[] = {'t', 'e','m','p','l','a','t','e'};
printArray<int, 5>(a);
cout<<"In mang 1 chieu so thuc \n";
printArray<float, 3>(b);
cout<<"in mang ky tu \n";
printArray<char,8>(str);
} tv3_array.cpp
Tìm giá trị lớn nhất của 3 số
template < class T >
T maximum ( T valuel , T value2 , T value3 )
{
T max = valuel ;
if (value2 > max)
max = value2 ;
if (value3 > max)
max = value3 ;

return max ;
}
int main()
{
int c;
c = maximum(3,5,7); // nội suy biết kiểu int
cout<<"Gia tri lon nhat "<<c<<endl;
system("pause");
return 0;
} tv1_max.cpp
Mở rộng

• Tìm địa chỉ của hàm nạp chồng


int absolute(int var);
float absolute(float var);
int main()
{
ivar = absolute(var1);
fvar = absolute(var2);
int (*pint)(int);
float(*pfloat)(float);

pint = absolute;
pfloat = absolute;
cout<<"Dia chi cua ham nap chong \n\n";
cout<<&pint<<" "<<&pfloat<<endl<<"\n";
}

You might also like