Tài liệu Chương 2: Hàm trong C++ - Pdf 91

chương 2
Hàm trong C++
Chương này trình bầy những khả năng mới của C++ trong việc xây
dựng và sử dụng hàm. Đó là:
+ Kiểu tham chiếu và việc truyền dữ liệu cho hàm bằng tham
chiếu.
+ Đối tham chiếu hằng (const)
+ Đối có giá trị mặc định
+ Hàm trực tuyến
+ Việc định nghĩa chồng các hàm
+ Việc định nghĩa chồng các toán tử
§
1. Biến tham chiếu (Reference variable)
1.1. Hai loại biến dùng trong C
Trước khi nói đến biến tham chiếu, chúng ta nhắc lại 2 loại biến
gặp trong C là:
Biến giá trị dùng để chứa dữ liệu (nguyên, thực, ký tự, ... )
Biến con trỏ dùng để chứa địa chỉ
Các biến này đều được cung cấp bộ nhớ và có địa chỉ. Ví dụ câu
lệnh khai báo:
double x , *px;
sẽ tạo ra biến giá trị kiểu double x và biến con trỏ kiểu double px.
Biến x có vùng nhớ 8 byte, biến px có vùng nhớ 4 byte (nếu dùng mô
hình Large). Biến x dùng để chứa giá trị kiểu double, ví dụ lệnh gán:
x = 3.14;
sẽ chứa giá trị 3.14 vào biễn x. Biến px dùng để chứa địa chỉ của một
biến thực, ví dụ câu lệnh:
px = &x ;
sẽ lưu trữ địa chỉ của biễn x vào con trỏ px.
1.2. Biến tham chiếu
Trong C++ cho phép sử dụng loại biến thứ ba là biến tham chiếu.

hàm để cho phép hàm truy nhập đến các tham số biến trong lời gọi
hàm.
Vài chú ý về biến tham chiếu:
a. Vì biến tham chiếu không có địa chỉ riêng, nó chỉ là bí danh của
một biến kiểu giá trị nên trong khai báo phải chỉ rõ nó tham chiếu đến
biến nào. Ví dụ nếu khai báo:
double &x ;
thì Trình biên dịch sẽ báo lỗi:
Reference variable ‘x’ must be initialized
b. Biến tham chiếu có thể tham chiếu đến một phần tử mảng, ví dụ:
int a[10] , &r = a[5];
r = 25 ; // a[5] = 25
c. Không cho phép khai báo mảng tham chiếu
d. Biến tham chiếu có thể tham chiếu đến một hằng. Khi đó nó sẽ
sử dụng vùng nhớ của hằng và nó có thể làm thay đổi giá trị chứa
trong vùng nhớ này.
Ví dụ nếu khai báo:
int &s = 23 ;
thì Trình biên dịch đưa ra cảnh báo (warning):
Temporary used to initialize 's'
Tuy nhiên chương trình vẫn làm việc. Các câu lệnh dưới đây vẫn
thực hiện và cho kết quả như sau:
s++;
cout << "\ns= " << s; // In ra s=24
Chương trình dưới đây minh hoạ cách dùng biến tham chiếu đến
một phần tử mảng cấu trúc để nhập dữ liệu và thực hiện các phép tính
trên các trường của phần tử mảng cấu trúc.
#include <iostream.h>
#include <conio.h>
struct TS

int y = 12, z ;
const int &py=y; // Hằng tham chiếu py tham chiếu đến biến y
y++; // Đúng
z = 2*py ; // Đúng z = 26
cout << y <<" "<< py; // In ra: 13 13
py=py+1; // Sai, Trình biên dịch thông báo lỗi:
// Cannot modify a const object
Cách dùng: Hằng tham chiếu cho phép sử dụng giá trị chứa trong
một vùng nhớ, nhưng không cho phép thay đổi giá trị này.
Hằng tham chiếu thường được sử dụng làm đối của hàm để cho
phép hàm sử dụng giá trị của các tham số trong lời gọi hàm, nhưng
tránh không làm thay đổi giá trị của các tham số.
§
2. Truyền giá trị cho hàm theo tham chiếu
2.1. Hàm trong C
Trong C chỉ có một cách truyền dữ liệu cho hàm theo giá trị :
+ Cấp phát vùng nhớ cho các đối.
+ Gán giá trị các tham số trong lời gọi hàm cho các đối sau đó hàm
làm việc trên vùng nhớ của các đối chứ không liên quan gì đến các
tham số.
Như vây chương trình sẽ tạo ra các bản sao (các đối) của các tham
số và hàm sẽ thao tác trên các bản sao này, chứ không làm việc trực
tiếp với các tham số. Phương pháp này có 2 nhược điểm chính:
Tốn kém về thời gian và bộ nhớ vì phải tạo ra các bản sao. Không
thao tác trực tiếp trên các tham số, vì vậy không làm thay đổi được giá
trị các tham số.
2.2. Truyền giá trị cho hàm theo tham chiếu
Trong C++ cung cấp thêm cách truyền dữ liệu cho hàm theo tham
chiếu bằng cách dùng đối là biến tham chiếu hoặc đối là hằng tham
chiếu. Cách này có ưu điểm:

}
void hv(double &x, double &y)
{
double tg=x; x=y; y= tg;
}
void sapxep(double * a, int n)
{
for (int i=1; i <= n-1 ;++i)
for (int j=i+1 ; j<=n ;++j)
if (a[i] > a[j])
hv(a[i],a[j]);
}
void main()
{
double x[100];
int i, n;
cout <<"\n N= ";
cin >> n;
nhapds(x,n);
sapxep(x,n);
for (i=1;i<=n;++i)
printf("\n%0.1lf",x[i]);
getch();
}
/*
Chương trình sau gồm các hàm:
- Nhập dẫy cấu trúc (mỗi cấu trúc chứa dữ liệu một thí sinh)
- Hoán vị 2 biến cấu trúc
- Sắp xếp dẫy thí sinh theo thứ tự giảm của tổng điểm
- In một cấu trúc (in họ tên và tổng điểm)

void hvts(TS &ts1, TS &ts2)
{
TS tg=ts1;
ts1=ts2;
ts2=tg;
}
void sapxep(TS *ts,int n)
{
for (int i=1;i<=n-1;++i)
for (int j=i+1;j<=n;++j)
if (ts[i].td < ts[j].td)
hvts(ts[i],ts[j]);
}
void main()
{
TS ts[100];
int n,i;
clrscr();
cout << " So thi sinh: " ;
cin >> n ;
nhapsl(ts,n);
sapxep(ts,n) ;
float dc;
cout << " Diem chuan: " ;
cin >> dc;
cout << "\n\nDanh sach trung tuyen\n" ;
for (i=1;i<=n;++i)
if (ts[i].td >= dc)
ints(ts[i]);
else

{
if (j==1) cout << "\n" ;
cout << setw(6) << a[i][j] ;
}
}
void maxminds(float *x, int n,int &vtmax, int &vtmin)
{
vtmax = vtmin = 1 ;
for (int i=2; i<=n ; ++i)
{
if (x[i] > x[vtmax]) vtmax = i;
if (x[i] < x[vtmin]) vtmin = i;
}
}
void main()
{
float a[20][20];
int m, n;
cout <<"\n So hamg va so cot ma tran: ";
cin >> m >> n;
nhapmt(a,m,n);
clrscr();
inmt(a,m,n);
float *p = (float*)a;
int vtmax, vtmin;
for (int i=1;i<=m;++i)
{
p = ((float*)a) + i*20 ;
maxminds(p , n, vtmax, vtmin) ;
printf("\nHang %d Phan tu max= %6.1f tai cot

#include <iostream.h>
#include <conio.h>
struct TS
{
char ht[25];
float t,l,h,td;
};
TS ts;
TS &f()
{
return ts;
}
void main()
{
TS &h=f(); // h tham chiếu đến biến ts
cout << "\n Ho ten: " ;
cin.get(h.ht,25) ;
cout << "Cac diem toan, ly, hoa: ";
cin >> h.t >> h.l >> h.h ;
h.td = h.t + h.l + h.h ;
cout << "\n Ho ten: " << ts.ht;
cout << "\n Tong diem: " << ts.td;
getch();
}
Ví dụ 3 trình bầy một hàm trả về bí danh của một phần tử mảng
cấu toàn bộ.
Hàm sẽ kiểm tra xem chỉ số mảng có vượt ra ngoài miền quy định
hay không. Sau đó dùng hàm này để truy nhập đến các phần tử mảng
cấu trúc.
#include <iostream.h>

{
if (i<1 || i>n)
{
cout << "Chi so mang khong hop le " ;
exit(1);
}
return ts[i];
}
void main()
{
int n, i ;
cout << "\n So thi sinh : " ;
cin >> n;
cap_phat_bo_nho_nhapsl(n);
while (1)
{
cout << "\nCan xem thi sinh thu may: " ;
cout << "\nChon so tu 1 den " << n << " (bam sai ket thuc
CT) ";
cin >> i;
TS &h=f(i,n);
cout << "\n Ho ten: " << h.ht;
cout << "\n Tong diem: " << h.td;
}
}
§
4. Đối có giá trị mặc định
4.1. Thế nào là đối mặc định
Một trong các khả năng mạnh của C++ là nó cho phép xây dựng
hàm với các đối có giá trị mặc định. Thông thường số tham số trong

d1, d2, d3, d4, d5
Khi đó:
nếu một đối mặc định thì phải là d5
nếu hai đối mặc định thì phải là d4, d5
nếu ba đối mặc định thì phải là d3, d4, d5
...
Các ví dụ sai:
d3 và d5 mặc định (khi đó d4 cũng phải mặc định)
d3 và d4 mặc định (khi đó d5 cũng phải mặc định)
+ Khi xây dựng hàm, nếu sử dụng khai báo nguyên mẫu, thì các
đối mặc định cần được khởi gán trong nguyên mẫu, ví dụ:
// Khởi gán giá trị cho 3 đối mặc định d3, d4 và d5)
void f(int d1, float d2, char *d3=”HA NOI”,
int d4 = 100, double d5=3.14) ;
void f(int d1, float d2, char *d3, int d4, double d5)
{
// Các câu lệnh trong thân hàm
}
Không được khởi gán lại cho các đối mặc định trong dòng đầu của
định nghĩa hàm. Nếu vi phạm điều này thì Chương trình dịch sẽ thông
báo lỗi.
+ Khi xây dựng hàm, nếu không khai báo nguyên mẫu, thì các đối
mặc định được khởi gán trong dòng đầu của định nghĩa hàm, ví dụ:
// Khởi gán giá trị cho 3 đối mặc định d3, d4 và d5)
void f(int d1, float d2, char *d3=”HA NOI”,
int d4 = 100, double d5=3.14)
{
// Các câu lệnh trong thân hàm
}
+ Giá trị dùng để khởi gán cho đối mặc đinh

void ht(char *dc , int n )
{
for (int i=0;i<n;++i)
cout << "\n" << dc;
}
void main()
{
ht(); // In dòng chữ “HA NOI” trên 10 dòng
ht("ABC",3); // In dòng chữ “ABC” trên 3 dòng
ht("DEF"); // In dòng chữ “DEF” trên 10 dòng
getch();
}
Ví dụ dưới đây trình bầy hàm hiển thị một chuỗi str trên màn hình
đồ hoạ, tại vị trí (x,y) và có mầu m. Các đối x, y và m là mặc định.
Dùng các hàm getmaxx() và getmaxy() để khởi gán cho x, y. Dùng
hằng RED gán cho m.
#include <conio.h>
#include <graphics.h>
void hiendc(char *str, int x=getmaxx()/2,
int y = getmaxy()/2, int m=RED);
void hiendc(char *str, int x,int y, int m)
{
int mau_ht = getcolor(); // Luu mau hien tai
setcolor(m);
outtextxy(x,y,str) ;
setcolor(mau_ht); // Khoi phuc mau hien tai
}
void main()
{
int mh=0, mode=0;

return s*h/2;
}
void main()
{
clrscr();
cout << setiosflags(ios::showpoint) << setprecision(2);
cout << "\nTich phan tu 0 den 1 cua x*x= " << tp() ;
cout << "\nTich phan tu 0 den 1 cua exp(x)= " << tp(exp);
cout << "\nTich phan tu 0 den PI/2 cua sin(x) " <<
tp(sin,0,3.14/2);
getch();
}
§
5. Các hàm trực tuyến (inline)
5.1. Ưu, nhược điểm của hàm
Việc tổ chức chương trình thành các hàm có 2 ưu điểm rõ rệt :
Thứ nhất là chia chương trình thành các đơn vị độc lập, làm cho
chương trình được tổ chức một cách khoa học dễ kiểm soát dễ phát
hiện lỗi, dễ phát triển, mở rộng.
Thứ hai là giảm được kích thước chương trình, vì mỗi đoạn
chương trình thực hiện nhiệm vụ của hàm được thay bằng một lời gọi
hàm.
Tuy nhiên hàm cũng có nhược điểm là làm chậm tốc độ chương
trình do phải thực hiện một số thao tác có tính thủ tục mỗi khi gọi
hàm như: Cấp phát vùng nhớ cho các đối và biến cục bộ, truyền dữ
liệu của các tham số cho các đối, giải phóng vùng nhớ trước khi thoát
khỏi hàm.
Các hàm trực tuyến trong C++ cho khả năng khắc phục được
nhược điểm nói trên.
5.2. Các hàm trực tuyến

{
return a*b;
}
Chú ý: Trong C++ , nếu hàm được xây dựng sau lời gọi hàm thì
bắt buộc phải khai báo nguyên mẫu hàm trước lời gọi. Trong ví dụ
trên, Trình biên dịch C++ sẽ bắt lỗi vì thiếu khai báo nguyên mẫu hàm
f .
5.3. Cách biên dịch hàm trực tuyến
Chương trình dịch xử lý các hàm inline như các macro (được định
nghĩa trong lệnh #define), nghĩa là nó sẽ thay mỗi lời gọi hàm bằng
một đoạn chương trình thực hiện nhiệm vụ của hàm. Cách này làm
cho chương trình dài ra, nhưng tốc độ chương trình tăng lên do không
phải thực hiện các thao tác có tính thủ tục khi gọi hàm.
5.4. So sánh macro và hàm trực tuyến
Dùng macro và hàm trực tuyến đều dẫn đến hiệu quả tương tự, tuy
nhiên người ta thích dùng hàm trực tuyến hơn, vì cách này đảm bảo
tính cấu trúc của chương trình, dễ sử dụng và tránh được các sai sót
lặt vặt thường gặp khi dùng #define (như thiếu các dấu ngoặc, dấu
chấm phẩy)
5.5. Khi nào thì nên dùng hàm trực tuyến
Phương án dùng hàm trực tuyến rút ngắn được thời gian chạy máy
nhưng lại làm tăng khối lượng bộ nhớ chương trình (nhất là đối với
các hàm trực tuyến có nhiều câu lệnh). Vì vậy chỉ nên dùng phương
án trực tuyến đối với các hàm nhỏ.
5.6. Sự hạn chế của Trình biên dịch
Không phải khi gặp từ khoá inline là Trình biên dịch nhất thiết
phải xử lý hàm theo kiểu trực tuyến.
Chú ý rằng từ khoá inline chỉ là một sự gợi ý cho Trình biên dịch
chứ không phải là một mệnh lệnh bắt buộc.
Có một số hàm mà các Trình biên dịch thường không xử lý theo


Nhờ tải bản gốc

Tài liệu, ebook tham khảo khác

Music ♫

Copyright: Tài liệu đại học © DMCA.com Protection Status