Bài giảng Ngôn ngữ lập trình C/C++ - Phạm Hồng Thái
Từ đó lập trình hướng đối tượng được xây dựng dựa trên đặc trưng chính là
khái niệm đóng gói. Đóng gói là khái niệm trung tâm của phương pháp lập trình
hướng đối tượng, trong đó dữ liệu và các thao tác xử lý nó sẽ được qui định trước
và "đóng" thành một "gói" thống nhất, riêng biệt với các dữ liệu khác tạo thành kiểu
dữ liệu với tên gọi là các lớp. Như vậy một lớp không chỉ chứa dữ liệu bình thường
như các kiểu dữ liệu khác mà còn chứa các thao tác để xử lý dữ liệu này. Các thao
tác được khai báo trong gói dữ liệu nào chỉ xử lý dữ liệu trong gói đó và ngược lại
dữ liệu trong một gói chỉ bị tác động, xử lý bởi thao tác đã khai báo trong gói đó.
Điều này tạo tính tập trung cao khi lập trình, mọi đối tượng trong một lớp sẽ chứa
cùng loại dữ liệu được chỉ định và cùng được xử lý bởi các thao tác như nhau. Mọi
lập trình viên khi làm việc với dữ liệu trong một gói đều sử dụng các thao tác như
nhau để xử lý dữ liệu trong gói đó. C++ cung cấp cách thức để tạo một cấu trúc dữ
liệu mới thể hiện các gói nói trên, cấu trúc dữ liệu này được gọi là lớp.
IV. TỔ CHỨC CHƯƠNG TRÌNH
1. Các loại biến và phạm vi
a. Biến cục bộ
Là các biến được khai báo trong thân của hàm và chỉ có tác dụng trong hàm này,
kể cả các biến khai báo trong hàm main() cũng chỉ có tác dụng riêng trong hàm main().
Từ đó, tên biến trong các hàm là được phép trùng nhau. Các biến của hàm nào sẽ chỉ
127
Chương 4. Hàm và chương trình
tồn tại trong thời gian hàm đó hoạt động. Khi bắt đầu hoạt động các biến này được tự
động sinh ra và đến khi hàm kết thúc các biến này sẽ mất đi. Tóm lại, một hàm được
xem như một đơn vị độc lập, khép kín.
Tham đối của các hàm cũng được xem như biến cục bộ.
Ví dụ 1 : Dưới đây ta nhắc lại một chương trình nhỏ gồm 3 hàm: luỹ thừa, xoá màn
hình và main(). Mục đích để minh hoạ biến cục bộ.
float luythua(float x, int n) // hàm trả giá trị xn
{
int i ;
float kq = 1;
for (i=1; i<=n; i++) kq *= x;
return kq;
}
void xmh(int n) // xoá màn hình n lần
{
int i;
for (i=1; i<=n; i++) clrscr();
}
main()
{
float x; int n;
cout > x >> n;
xmh(5); // xoá màn hình 5 lần
cout << luythua(x, n); // in xn
}
Qua ví dụ trên ta thấy các biến i, đối n được khai báo trong hai hàm: luythua() và
xmh(). kq được khai báo trong luythua và main(), ngoài ra các biến x và n trùng với đối
của hàm luythua(). Tuy nhiên, tất cả khai báo trên đều hợp lệ và đều được xem như
khác nhau. Có thể giải thích như sau:
− Tất cả các biến trên đều cục bộ trong hàm nó được khai báo.
128
Chương 4. Hàm và chương trình
− x và n trong main() có thời gian hoạt động dài nhất: trong suốt quá trình chạy
chương trình. Chúng chỉ mất đi khi chương trình chấm dứt. Đối x và n trong
luythua() chỉ tạm thời được tạo ra khi hàm luythua() được gọi đến và độc lập
với x, n trong main(), nói cách khác tại thời điểm đó trong bộ nhớ có hai biến
x và hai biến n. Khi hàm luythua chay xong biến x và n của nó tự động biến
mất.
− Tương tự 2 đối n, 2 biến i trong luythua() và xoá màn hình cũng độc lập với
nhau, chúng chỉ được tạo và tồn tại trong thời gian hàm của chúng được gọi và
hoạt động.
b. Biến ngoài
Là các biến được khai báo bên ngoài của tất cả các hàm. Vị trí khai báo của
chúng có thể từ đầu văn bản chương trình hoặc tại một một vị trí bất kỳ nào đó giữa
văn bản chương trình. Thời gian tồn tại của chúng là từ lúc chương trình bắt đầu chạy
đến khi kết thúc chương trình giống như các biến trong hàm main(). Tuy nhiên về
phạm vi tác dụng của chúng là bắt đầu từ điểm khai báo chúng đến hết chương trình,
tức tất cả các hàm khai báo sau này đều có thể sử dụng và thay đổi giá trị của chúng.
Như vậy các biến ngoài được khai báo từ đầu chương trình sẽ có tác dụng lên toàn bộ
chương trình. Tất cả các hàm đều sử dụng được các biến này nếu trong hàm đó không
có biến khai báo trùng tên. Một hàm nếu có biến trùng tên với biến ngoài thì biến ngoài
bị che đối với hàm này. Có nghĩa nếu i được khai báo như một biến ngoài và ngoài ra
trong một hàm nào đó cũng có biến i thì như vậy có 2 biến i độc lập với nhau và khi
hàm truy nhập đến i thì có nghĩa là i của hàm chứ không phải i của biến ngoài.
Dưới đây là ví dụ minh hoạ cho các giải thích trên.
Ví dụ 2 : Chúng ta xét lại các hàm luythua() và xmh(). Chú ý rằng trong cả hai hàm này
đều có biến i, vì vậy chúng ta có thể khai báo i như một biến ngoài (để dùng chung cho
luythua() và xmh()), ngoài ra x, n cũng có thể được khai báo như biến ngoài. Cụ thể:
#include
#include
float x; int n; int i ;
float luythua(float x, int n)
{
float kq = 1;
for (i=1; i<=n; i++) kq *= x;
}
129
Chương 4. Hàm và chương trình
void xmh()
{
for (i=1; i<=n; i++) clrscr();
}
main()
{
cout > x >> n;
xmh(5); // xoá màn hình 5 lần
cout << luythua(x, n); // in xn
}
Trong ví dụ này ta thấy các biến x, n, i đều là các biến ngoài. Khi ta muốn sử
dụng biến ngoài ví dụ i, thì biến i sẽ không được khai báo trong hàm sử dụng nó.
Chẳng hạn, luythua() và xmh() đều sử dụng i cho vòng lặp for của mình và nó không
được khai báo lại trong 2 hàm này. Các đối x và n trong luythua() là độc lập với biến
ngoài x và n. Trong luythua() khi sử dụng đến x và n (ví dụ câu lệnh kq *= x) thì đây là
x của hàm chứ không phải biến ngoài, trong khi trong main() không có khai báo về x
và n nên ví dụ câu lệnh cout << luythua(x, n); là sử dụng x, n của biến ngoài.
Nói chung trong 2 ví dụ trên chương trình đều chạy tốt và như nhau. Tuy nhiên,
việc khai báo khác nhau như vậy có ảnh hưởng hoặc gây nhầm lẫn gì cho người lập
trình ? Liệu chúng ta có nên tự đặt ra một nguyên tắc nào đó trong khai báo biến ngoài
và biến cục bộ để tránh những nhầm lẫn có thể xảy ra. Chúng ta hãy xét tiếp cũng ví dụ
trên nhưng thay đổi một số khai báo và tính 23 (có thể bỏ bớt biến n) như sau:
#include
#include
float x; int i ; // không dùng n
float luythua(float x, int n)
{
float kq = 1;
for (i=1; i<=n; i++) kq *= x;
}
void xmh()
{
130
Chương 4. Hàm và chương trình
for (i=1; i<=n; i++) clrscr();
}
main()
{
x = 2;
i = 3;
xmh(5); // xoá màn hình 5 lần
cout << luythua(x, i); // in xi, kết quả x = 23 = 8 ?
}
Nhìn vào hàm main() ta thấy giá trị 23 được tính bằng cách đặt x = 2, i = 3 và gọi
hàm luythua(x,i). Kết quả ta mong muốn sẽ là giá trị 8 hiện ra màn hình, tuy nhiên
không đúng như vậy. Trước khi in kết quả này ra màn hình hàm xmh() đã được gọi đến
để xoá màn hình. Hàm này sử dụng một biến ngoài i để làm biến đếm cho mình trong
vòng lặp for và sau khi ra khỏi for (cũng là kết thúc xmh()) i nhận giá trị 6. Biến i
ngoài này lại được sử dụng trong lời gọi luythua(x,i) của hàm main(), tức tại thời điểm
này x = 2 và i = 6, kết quả in ra màn hình sẽ là 26 = 64 thay vì 8 như mong muốn.
Tóm lại "điểm yếu" dẫn đến sai sót của chương trình trên là ở chỗ lập trình viên
đã "tranh thủ" sử dụng biến i cho 2 hàm xmh() và main() (bằng cách khai báo nó như
biến ngoài) nhưng lại với mục đích khác nhau. Do vậy sau khi chạy xong hàm xmh() i
bị thay đổi khác với giá trị i được khởi tạo lúc ban đầu. Để khắc phục lỗi trong chương
trình trên ta cần khai báo lại biến i: hoặc trong main() khai báo thêm i (nó sẽ che biến i
ngoài), hoặc trong cả hai xmh() và main() đều có biến i (cục bộ trong từng hàm).
Từ đó, ta nên đề ra một vài nguyên tắc lập trình sao cho nó có thể tránh được
những lỗi không đáng có như vậy:
• nếu một biến chỉ sử dụng vì mục đích riêng của một hàm thì nên khai báo
biến đó như biến cục bộ trong hàm. Ví dụ các biến đếm của vòng lặp, thông
thường chúng chỉ được sử dụng thậm chí chỉ riêng trong vòng lặp chứ cũng
chưa phải cho toàn bộ cả hàm, vì vậy không nên khai báo chúng như biến
ngoài. Những biến cục bộ này sau khi hàm kết thúc chúng cũng sẽ kết thúc,
không gây ảnh hưởng đến bất kỳ hàm nào khác. Một đặc điểm có lợi nữa cho
khai báo cục bộ là chúng tạo cho hàm tính cách hoàn chỉnh, độc lập với mọi
hàm khác, chương trình khác. Ví dụ hàm xmh() có thể mang qua chạy ở
chương trình khác mà không phải sửa chữa gì nếu i đã được khai báo bên
trong hàm. Trong khi ở ví dụ này hàm xmh() vẫn hoạt động được nhưng trong
chương trình khác nếu không có i như một biến ngoài (để xmh() sử dụng) thì
hàm sẽ gây lỗi.
131
Chương 4. Hàm và chương trình
• với các biến mang tính chất sử dụng chung rõ nét (đặc biệt với những biến
kích thước lớn) mà nhiều hàm cùng sử dụng chúng với mục đích giống nhau
thì nên khai báo chúng như biến ngoài. Điều này tiết kiệm được thời gian cho
người lập trình vì không phải khai báo chúng nhiều lần trong nhiều hàm, tiết
kiệm bộ nhớ vì không phải tạo chúng tạm thời mỗi khi chạy các hàm, tiết
kiệm được thời gian chạy chương trình vì không phải tổ chức bộ nhớ để lưu
trữ và giải phóng chúng. Ví dụ trong chương trình quản lý sinh viên (chương
6), biến sinh viên được dùng chung và thống nhất trong hầu hết các hàm (xem,
xoá, sửa, bổ sung, thống kê ) nên có thể khai báo chúng như biến ngoài,
điều này cũng tăng tính thống nhất của chương trình (mọi biến sinh viên là
như nhau cho mọi hàm con của chương trình).
Tóm lại, nguyên tắc tổng quát nhất là cố gắng tạo hàm một cách độc lập, khép
kín, không chịu ảnh hưởng của các hàm khác và không gây ảnh hưởng đến hoạt động
của các hàm khác đến mức có thể.
2. Biến với mục đích đặc biệt
a. Biến hằng và từ khoá const
Để sử dụng hằng có thể khai báo thêm từ khoá const trước khai báo biến. Phạm vi
và miền tác dụng cũng như biến, có nghĩa biến hằng cũng có thể ở dạng cục bộ hoặc
toàn thể. Biến hằng luôn luôn được khởi tạo trước.
Có thể khai báo từ khoá const trước các tham đối hình thức để không cho phép
thay đổi giá trị của các biến ngoài (đặc biệt đối với với mảng và xâu kí tự, vì bản thân
các biến này được xem như con trỏ do đó hàm có thể thay đổi được giá trị của các biến
ngoài truyền cho hàm này).
Ví dụ sau thể hiện hằng cũng có thể được khai báo ở các phạm vi khác nhau.
const int MAX = 30; // toàn thể
void vidu(const int *p) // cục bộ
{
const MAX = 10; // cục bộ
}
void main()
{
const MAX = 5; // cục bộ
132
Chương 4. Hàm và chương trình
}
Trong Turbo C, BorlandC và các chương trình dịch khác có nhiều hằng số khai
báo sẵn trong tệp values.h như MAXINT, M_PI hoặc các hằng đồ hoạ trong graphics.h
như WHITE, RED,
b. Biến tĩnh và từ khoá static
Được khai báo bằng từ khoá static. Là biến cục bộ nhưng vẫn giữ giá trị sau khi
ra khỏi hàm. Phạm vi tác dụng như biến cục bộ, nghĩa là nó chỉ được sử dụng trong
hàm khai báo nó. Tuy nhiên thời gian tác dụng được xem như biến toàn thể, tức sau khi
hàm thực hiện xong biến vẫn còn tồn tại và vẫn lưu lại giá trị sau khi ra khỏi hàm. Giá
trị này này được tiếp tục sử dụng khi hàm được gọi lại, tức biến static chỉ được khởi
đầu một lần trong lần chạy hàm đầu tiên. Nếu không khởi tạo, C++ tự động gán giá trị
0 (ngầm định = 0). Ví dụ:
int i = 1;
void bp()
{
static int lanthu File đính kèm:
NGon ngu lap trinh CC.pdf



