I. Mở đầu
Như ta đã biết, trong các đời sống cũng như trong mọi lĩnh vực, luôn có các giá trị không thể thay đổi gọi là hằng số,
Vd: số π với 100 chữ sô thập phân:
3,141592653589793238462643383279502884197169399375 10582097494459230781640628620899862803482534211706 79
Vấn đề là trong tin học, cứ mỗi khi dùng đến giá trị π thì chả lẽ cứ viết hết tất cả các chử số???
II. Hằng
Nếu dùng một biến để lưu trữ giá trị của hằng số thì có một vấn đề là biến thì thay đổi được giá trị ==>lỗi.
VD:
C++ Code:
- float PI=3.14;
- //////
- PI=8;
- //////
Loại lỗi này rất khó nhận thấy nhưng để lại hậu quả rất to lớn. nếu sau đó ta không chú ý cứ dùng biến đó trên các đoạn mã cần số π, vậy ta phải dùng hằng để khai báo cho giá trị này.
a. Khai báo hằng:
Có 2 cách khai báo hằng
- Dùng chỉ thị #define:
Code:
#define A "gia tri"
chỉ thị #define còn có nhiều tác dụng khác.
- Dùng từ khóa const:
Code:
const kiểu tên_hằng=giá_trí; kiểu const tên_hằng=giá_trí;
C++ Code:
- const int x=8;
Sau khi khai báo thì ta không thể thay đổi x, ví dụ:
C++ Code:
- x=8; //lỗi
III. Từ khóa const trong C++
Như ta đã biết ở trên, từ khóa const dùng để khai báo hằng:
const kiểu tên_hằng=giá_trí;
kiểu const tên_hằng=giá_trí;
VD:
C++ Code:
- const int x=8;
- int const y=4;
Câu trả lời là có.
1. Từ khóa const với con trỏ
Đối với biến con trỏ ta nên phân biệt hai điều: vùng nhớ con trỏ trỏ đến và giá trị của vùng nhớ đó.
Vd:
C++ Code:
- int x = 10, y = 20;
- const int *px = &x;
C++ Code:
- *px = 15;// lỗi
- px = &y;
- x = 16;
Vì ta dùng *px để thay đỏi giá trị của vùng nhớ mà px đang trỏ đến.
Chú ý: Giá trị của x vẫn có thể được thay đổi, ta chỉ không thể thay đổi giá trị này thông qua px.
Nhưng với các khai báo sau:
C++ Code:
- int x = 10, y = 20;
- int* const px = &x;
C++ Code:
- *px=y;
- *px=&y;//lỗi
Với khai báo sau:
C++ Code:
- int x = 10;
- const int* const px = &x;
2. Từ khóa const với đối tượng
Giả sử ta có lớp với hàm tạo sau:
C++ Code:
- class A
- {
- int a;
- public:
- A(int t=0){a=t;}
- //...
- };
Để khai báo hằng đối tượng ta dùng từ khóa const như sau:
C++ Code:
- A const a(4);
- const A b;
VD: ta có hàm sau
C++ Code:
- void A::set(int x)
- {
- a=x;
- }
b. Tham chiếu hằng, con trỏ hằng
Giả sử có hàm có đối tượng đầu vào sau
Code:
type C(A a) { //Các câu lệnh }
Vì vậy người ta thường dùng tham số chuyền vào là con trỏ hay tham chiếu:
Code:
type C(A *a) { //Các câu lệnh }
Code:
type C(A &a) { //Các câu lệnh }
Nhưng với khai báo như thế thì giá trị của biến truyền vào có thể bị thay đổi thông qua biến object (vì là biến con trỏ hoặc tham chiếu), trong khi với cách khai báo như cũ thì ta không hề muốn giá trị này bị sửa đổi chút nào. Do đó, từ khóa const được sử dụng:
Code:
type C(const A *a) { //Các câu lệnh }
Code:
type C(const A &a) { //Các câu lệnh }
2. Hàm trả về con trỏ có thể có dạng
C++ Code:
- const A* functionName(/*các đối số*/);
C++ Code:
- A const * functionName(/*các đối số*/);
C++ Code:
- const A *const functionName(/*các đối số*/);
c. Phương thức hằng.
Ở trên ta đã nhắc đến phương thức hằng, vậy phương thức hằng là gì? Tác dụng của nó?
Như ta đã biêt, một hằng đối tượng thì không thể thay đổi các thuộc tính của nó và không được phép gọi các phương thức có thể làm thay đổi các thuộc tính của nó, trừ trường hợp đặc biệt: các thuộc tính mutable. các phương thức được các hằng đối tượng sử dụng gọi là phương thức hằng, hay nói cách khác, các hằng đối tượng chỉ làm việc trên các phương thức hằng.
Giả sử với lớp A có một phương thức print() như sau:
C++ Code:
- class A
- {
- int a;
- public:
- A(int t=0){a=t;}
- //...
- void print();
- };
C++ Code:
- void A::print()
- {
- }
Giả sử ta có 2 câu lệnh sau:
C++ Code:
- const A a;
- a.print();//////lỗi
Ta thấy trong hàm print() không hề có lệnh thay đổi thuộc tính???
Lí do là trình dịch không thể biết được là ta có thay đổi thuộc tính hay không ở phương thức không hằng vì một phương thức không hằng có thể thay đổi được thuộc tính.
Vậy làm sao để có thể cho hàm trên thực hiện được với hằng đối tượng?
Ta phải khai báo hàm print() là một phương thức hằng bằng cách thêm từ khóa const vào sau khai báo của nó trong khai báo lớp như sau:
C++ Code:
- void print() const;
C++ Code:
- class A
- {
- int a;
- public:
- A(int t=0){a=t;}
- //...
- void print() const;
- };
C++ Code:
- const A a;
- a.print();//////OK
VD:
C++ Code:
- void A::print()
- {
- a=7; //////lỗi
- }
Điều này khá hay trong môi trường làm việc cộng tác. Nếu nhiều người cùng xây dựng một lớp: thì cần xác định cái gì cần thay đổi, thay đổi bằng phương thức nào?…
Ở trên có nhắc đến thuộc tính mutable. Vậy thuộc tính này là gì?
Ta đã biết một phương thức hằng thì không được thay đổi các thuộc tính của đối tượng gọi nó. nhưng đôi khi cần phải thay đổi các thuộc tính này thông qua phương thức hằng, kể cả hằng đối tượng, khi đó chỉ cần khai báo trước thuộc tính đó từ khóa mutable.
Vậy nếu ta muốn có một phương thức hằng trả về một con trỏ không thể thay đổi giả trị của vùng nhớ, cũng như vùng nhớ mà con trỏ ấy đang trỏ tới, có tham số đầu vào là một con trỏ cũng không thể thay đổi giả trị của vùng nhớ, và vùng nhớ mà nó trỏ tới thì ta có một câu lệnh khai báo như sau:
C++ Code:
- const A *const functionName(const A * const) const; //5 từ const!!
UPDATE
trong C++ giả sử có hàm:
Code:
type1 ham(type&);//không thay đổi đối số trong thân hàm nha
Code:
ham(6);////////loi
Vì 6 là 1 hằng.
bạn cần khai báo tường minh hơn.
Và khi đó cần thay đổi hàm này như sau
Code:
type1 ham(const type&);/////////
0 comments: