May 1, 2012

Hằng, các vấn đề xung quanh.


Một hôm rảnh rỗi tìm hiểu về cái này. Một khái niệm quá phổ biến, nhưng trong một số ngôn ngữ lập trình, C/C++ chẳng hạn, thì cần phải tìm hiểu một cách rõ ràng.

Định nghĩa: Constant là một giá trị xác định không thể bị thay đổi trong suốt quá trình chạy của chương trình. (Nguồn).
Khai báo: Có 3 cách thông dụng:
  • Trực tiếp.
  • Dùng macro: #define.
  • Dùng từ khóa const.
Sự khác biệt đáng chú ý là macroconst. Ví dụ #define A 200const int A = 200; Macro đơn giản chỉ là trước khi dịch chương trình, trình compile sẽ thay thế (replace) tất cả các ký tự 'A' thành '200' cho hợp ngữ. Còn const thì khác, nó sẽ cấp phát 1 vùng nhớ có kích thước của int và gán giá trị của nó là 200, đồng thời vùng nhớ đó không thể bị thay đổi trong lúc chương trình chạy.

Tọa đàm đôi chút về hằng trong C++:
Cú pháp:
Const int x = 5 hay int const x = 5 là tương đương nhau, tuy nhiên, sẽ là rất khác với kiểu con trỏ (pointer).
Const pointer:
Cho đoạn code ví dụ sau:
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
    const int x = 5; 
    int y = 5;
 
    const int *px = &x; //(1) similar: int const *px = &x;
//    int* ppx = &x;
    int *py = &y; // (2)
    const int* ppy = &y;
    const int* const cpx = &x;
    int * const cpy = &y;
    //++x;
    ++y;
    ++px;
    ++py;
    //++cpx;
    //++cpy;
    //++(*ppy);
    //++y;
    return 0;    
}

Có một số điều cần nói ở code:


  • x  là một hằng, không thể thay đổi giá trị của nó được.

  • y là một biến.

  • px là biến con trỏ, nó trỏ đến hằng x và hằng này có kiểu là int nên kiểu dữ liệu của nó là const int* (int const* tương đương).

  • py : biến con trỏ, trỏ đến kiểu int.

  • cpx: hằng con trỏ, trỏ đến đến kiểu "const int".

  • cpy: hằng con trỏ, trỏ đến kiểu "int".

Vậy nên khi viết "int* px = &x" sẽ bị báo lỗi không thể chuyển (converion) được.

Còn nếu viết const int* ppy=&y thì sao?

Ở đây y vẫn là biến, tuy nhiên, ppy sẽ là biến con trỏ, nhưng (*ppy) lại là hằng. Thành ra ++ppy thì ok nhưng ++(*ppy) bị báo lỗi.

Điều cần lưu ý ở đây là xác định rõ, đâu là con trỏ hằng, và đâu là hằng con trỏ.

Chuỗi ký tự: Đâu là sự khác nhau giữa 2 dòng code sau:

char* ch = "Hello"; //(1)

char chs[] = "Hello"; //(2)

Ở (1), ch là một biến con trỏ kiểu cha, và nó có giá trị là địa chỉ đầu tiên của "Hello" (tức là 'H') và "Hello" là một chuỗi hằng, không thể thay đổi được.

chs[] lại khác, nó là một biến chuỗi kí tự và có thể thay đổi giá trị các thành phần trong đó được.

Hàm hằng:

Công thức:

<return-value> <class>::<member-function>(<args>) const

{

        // ...

}



Một số lưu ý:
  • Hàm này phải là một method trong class.
  • Không sử dụng với các phương thức tạo lập (constructor) và phương thức hủy (destructor)
  • Hàm này chỉ đọc (read-only): hàm không thể thay đổi giá trị mà đối tượng nó gọi đến.
  • Mọi đối tượng (non-const hay const) đều có thể gọi hàm này.
  • Đối tượng hằng (const obj) chỉ có thể gọi được các hàm hằng.

Ví dụ:

#include <iostream>
class Num{
private:
    int a;
 
public: 
    Num(int X){
        a = X;
    };
    int GetNum() const { return a;}
    void SetNum(int A) {this->a = A;}
};
int main() {
    Num num1(1);
    const Num num2(1);
    num1.SetNum(2);
    std::cout<< num1.GetNum()<< std::endl;    
    std::cout << num2.GetNum() << std::endl;
    num2.SetNum(4);
 
    return 0;
}