Từ khóa static trong C++

Chào các bạn đang theo dõi khóa học lập trình trực tuyến từ ngữ ₵++.

Trong chương làm chủ mã nguồn này, tất cả chúng ta sẽ cùng tìm tòi 1 số cách căn bản để:

  • Tổ chức mã nguồn hiệu quả hơn.
  • Tập làm quen với cách làm việc trong một nhóm cho một dự án nhỏ.

Nhưng trước tiên, mình xin giới thiệu với các bạn một từ khóa gây bối rối cho nhiều bạn mới học lập trình: static. Nó khó hiểu bởi những ý nghĩa khác nhau tùy theo nơi từ khóa này được sử dụng.

Các bạn chắc hẳn đã tìm tòi về định nghĩa biến toàn cục (global variable) trong bài học phạm vi của biến rồi phải không? Biến toàn cục được khai báo bên ngoài những khối lệnh (scope), có thể được truy xuất tại nhiều khối lệnh khác nằm bên dưới biến đó trong cùng một file chương trình (Để truy xuất tại các file chương trình khác, tất cả chúng ta sẽ cùng tìm tòi trong các bài sau).

Từ khóa static có thể được sử dụng để khai báo biến, dù đặt bên trong hay bên ngoài những khối lệnh, vẫn làm cho biến đó có hiệu lực cũng giống như biến toàn cục.

Từ khóa static còn tồn tại thể được sử dụng trong việc khái niệm hàm, các tính chất & bí quyết trong một lớp (class).

Biến static (static variables)

Biến static được tạo thành bên trong một khối lệnh có khả năng cất giữ giá trị của nó cho dù chương trình đã chạy ra bên ngoài khối lệnh chứa nó.

Xem Thêm  Python: Tách một chuỗi trên nhiều dấu phân cách • dữ liệu - python chia chuỗi thành danh sách bằng dấu phân cách

Biến static chỉ cần được khai báo một lần duy nhất, & tiếp tục được duy trì sự tồn tại xuyên suốt cho đến khi chương trình chấm dứt.

Dưới đây là một chẳng hạn dễ dàng cho thấy sự độc đáo giữa việc sử dụng biến cục bộ & biến static:

#include <iostreamvàgt;
 
void incrementAndPrint()
{
    int value = 1; // automatic duration by default
    ++value;
    std::cout << value << 'ɳ';
} // value is destroyed here
 
int main()
{
    incrementAndPrint();
    incrementAndPrint();
    incrementAndPrint();
    
    return 0;
}

Mỗi khi hàm incrementAndPrint được gọi, một biến có cái tên “value” được tạo thành & được gán giá trị 1. Hàm incrementAndPrint sẽ tăng giá trị của biến “value” lên 1 nhà cung cấp, giá trị in ra màn hình là 2. Khi hàm incrementAndPrint thực hiện xong tác vụ, biến “value” bị hủy. Cứ thực hiện liên tiếp như thế, kết quả in ra màn hình là:

2
2
2

Hiện tại, tất cả chúng ta thêm từ khóa static trước nơi biến “value” được khai báo:

#include <iostreamvàgt;
 
void incrementAndPrint()
{
    static int s_value = 1; // static duration variable
    ++s_value;
    std::cout << s_value << 'ɳ';
} // s_value is not destroyed here, but became inaccessible
 
int main()
{
    incrementAndPrint();
    incrementAndPrint();
    incrementAndPrint();
    
    return 0;
}

Lần này, vì biến “s_value” được khai báo với từ khóa static, nó sẽ chỉ được khởi tạo một lần duy nhất, dù hàm incrementAndPrint được gọi nhiều lần. Mỗi lần hàm incrementAndPrint được gọi, giá trị của biến “s_value” được tăng thêm 1, & còn được cất giữ lại đó cho đến khi chương trình chấm dứt. Kết quả in ra như sau:

2
3
4

Hàm static (static functions)

Từ khóa static cũng có thể được sử dụng cho các hàm, thường là những hàm được đặt bên trong các struct hoặc class (gọi là bí quyết). Trong bài học này, mình lấy một chẳng hạn về việc sử dụng hàm static bên trong một struct mẫu như sau:

#include <iostreamvàgt;

struct Check
{
	static void foo()
	{
		std::cout << "Called static function: foo" << std::endl;
	}
};

int main()
{
	Check::foo();
	return 0;
}

Các bạn có thể thấy, hàm foo được gọi mà không cần tạo thành thực thể kiểu Check.

Xem Thêm  làm thế nào để tạo một lược đồ xsd cho xml này? - cách tạo lược đồ xsd từ tệp xml

Điểm đáng cảnh báo trong việc sử dụng hàm static trong struct/class là chúng chẳng thể truy xuất đến non-static members trong struct/class đó:

struct Check
{
	int value;

	void nonstatic_foo()
	{
	}

	static void foo()
	{
		value = 1; // error
		nonstatic_foo(); // error
	}
};

Ưu/khuyết điểm khi sử dụng từ khóa static

Điều trước hết mình mong muốn kể tới là khuyết điểm khi sử dụng nhiều biến static trong một chương trình, đặc biệt hơn là lúc đặt biến static ngoài các khối lệnh tương tự với biến toàn cục. Điều này làm cho chương trình chẳng những trở nên rườm rà, khó kiểm tra hơn, nhưng còn gây phung phí bộ nhớ lưu trữ trong suốt thời gian chương trình đang chạy.

Các bạn thử tưởng tượng nếu khai báo một biến static kiểu mảng như thế:

static bool pressedKeys[1024];

Dù có đang sử dụng chúng hay không, chúng vẫn ở đó & chiếm một diện tích không nhỏ trên vùng nhớ.

Trong các bài học kế tiếp, tất cả chúng ta tìm tòi về viết những chương trình dễ dàng & phân bố mã nguồn trong nhiều file, nếu mỗi file tất cả chúng ta đều có khai báo biến static trong đó, thật khó kiểm tra.

Không những thế, không phải do rãnh rỗi mà người ta làm nên kiểu biến static, có một số trường hợp ứng dụng biến static khá tiện dụng. Mình lấy một chẳng hạn dễ dàng như sau:

int generateID()
{
	static int s_id = 0;
	return ++s_id;
}

struct Employee
{
	int ID;
	Employee()
	{
		ID = generateID();
	}
};

int main()
{
	Employee emp1;
	Employee emp2;
	Employee emp3;

	return 0;
}

Trong chương trình trên, hàm generateID có tính năng ra đời ID khi có đối tượng Employee mới được tạo thành. Như thế, tất cả chúng ta không lo về việc ID của đối tượng Employee mới bị trùng lặp. Bằng cách khai báo biến “s_id” bên trong hàm generateID, nó chẳng thể truy xuất hoặc biến đổi từ phía các hàm khác.

Xem Thêm  Liên kết qua điện thoại: Cách thêm liên kết & CTA “có thể gọi” vào trang web của bạn - thêm liên kết điện thoại html

Ngoài ra, từ khóa static hay được dùng thông dụng trong khi kiến trúc chương trình có chứa Singleton thiết kế pattern.

Kết luận

Trên đây không phải là toàn bộ những gì mình biết về từ khóa static. Nó có nhiều ích lợi trong khi kiến trúc chương trình, nhưng sẽ gây một tí rườm rà nếu dùng quá nhiều biến static trong một chương trình lớn.

Hẹn hội ngộ các bạn trong bài học kế tiếp trong khóa học lập trình ₵++ hướng thực hành.

Mọi quan niệm đóng góp hoặc khúc mắc có thể đặt thắc mắc trực tiếp tại diễn bầy.

www.daynhauhoc.com

Viết một bình luận