Để hiểu điều này, bạn nên có một hiểu biết tốt về compiling and linking, và sự khác biệt giữa declarations and definitions.
Hãy xem xét các lớp sau đây:
//In header file
class Example {
static bool exampleStaticMember;
};
Ở đây, exampleStaticMember
được khai báo nhưng không được định nghĩa. Điều này có nghĩa rằng nếu exampleStaticMember
được sử dụng theo cách có nghĩa là nó phải có địa chỉ thì phải có định nghĩa riêng cho nó. Nói chung, không có tuyên bố của một thành viên dữ liệu tĩnh trong định nghĩa lớp là định nghĩa của thành viên đó.
Khai báo bắt buộc thường được đặt trong tệp cpp chứa các định nghĩa khác cho các thành viên của lớp. Nó phải ở trong cùng một không gian tên như định nghĩa lớp. Định nghĩa thường trông giống như:
//In source file:
//This may optionally have an initialiser (eg "= true")
bool Example::exampleStaticMember;
định nghĩa có thể được đặt ở bất kỳ tập tin cpp, nhưng nó không nên được đặt trong tiêu đề với lớp, bởi vì điều đó sẽ có khả năng phá vỡ các One Definition Rule.
Là một trường hợp đặc biệt, nếu biến thành viên tĩnh là một const không thể thiếu hoặc liệt kê loại sau đó nó có thể có một initialiser trong định nghĩa lớp:
//In header file
class Example {
static const int initialised = 15;
};
Trong trường hợp này, định nghĩa trong file cpp là vẫn được yêu cầu nhưng không được phép có người khởi tạo:
//In source file
//Note: no initialiser!
const int Example::initialised;
Thành viên tĩnh đã được khởi tạo như thế này có thể được sử dụng trong biểu thức không đổi.
Templates
Đối với một thành viên dữ liệu tĩnh của một mẫu, điều hơi khác nhau. Thành viên tĩnh phải được xác định trong tiêu đề cùng với phần còn lại của lớp:
//In header file
template<typename T>
class Example {
static int exampleInt;
static T exampleT;
}
template<typename T> int Example<T>::exampleInt;
template<typename T> T Example<T>::exampleT;
Điều này hoạt động vì có ngoại lệ cụ thể cho Quy tắc một định nghĩa cho thành phần dữ liệu tĩnh của mẫu lớp.
Các ứng dụng khác của tĩnh
Khi từ khóa static
được áp dụng cho các chức năng và các đối tượng mà không phải là trong một phạm vi lớp học có thể mất trên một ý nghĩa rất khác nhau.
Khi áp dụng cho các đối tượng trong phạm vi chức năng, nó khai báo đối tượng được khởi tạo trong lần thực thi đầu tiên của hàm và sau đó giữ giá trị của nó giữa các cuộc gọi hàm.
Khi áp dụng cho các đối tượng hoặc hàm tại phạm vi không gian tên (bên ngoài bất kỳ định nghĩa lớp hoặc chức năng nào), nó khai báo đối tượng hoặc hàm với internal linkage. Việc sử dụng này không được chấp nhận cho các đối tượng vì số unnamed-namespace cung cấp giải pháp thay thế tốt hơn.
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12 – PlasmaHH