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