2010-09-13 48 views
44

Tôi muốn biết sự khác nhau giữa các biến tĩnh trong tệp tiêu đề so với khai báo trong một lớp. Khi biến tĩnh được khai báo trong một tệp tiêu đề là phạm vi của nó được giới hạn trong tệp .h hoặc trên tất cả các đơn vị. Nói chung biến tĩnh được khởi tạo trong tệp .cpp khi được khai báo trong lớp phải không? Vậy điều đó có nghĩa là phạm vi biến tĩnh được giới hạn trong 2 đơn vị biên dịch?Biến tĩnh trong C++

+5

Từ khóa 'tĩnh' quá tải.Nó có nghĩa là differntly ở những nơi khác nhau. Đó là lý do tại sao nó làm cho một câu hỏi thú vị để hỏi tại các cuộc phỏng vấn. – vrdhn

+0

Chắc chắn nằm trong số các ứng dụng hàng đầu, cùng với các hàm trừu tượng/lớp trừu tượng và các công cụ như thừa kế công khai/được bảo vệ/riêng tư. ;-) – DevSolar

Trả lời

67

Xin lỗi khi tôi trả lời các câu hỏi của bạn không đúng trật tự, nó giúp bạn dễ hiểu hơn theo cách này.

Khi biến tĩnh được khai báo trong tệp tiêu đề là phạm vi được giới hạn trong tệp .h hoặc trên tất cả các đơn vị.

Không có điều gì như "phạm vi tệp tiêu đề". Tệp tiêu đề được bao gồm vào tệp nguồn. Đơn vị dịch là tệp nguồn bao gồm văn bản từ tệp tiêu đề. Bất cứ điều gì bạn viết trong một tệp tiêu đề được sao chép vào mỗi tệp nguồn.

Như vậy, biến tĩnh được khai báo trong tệp tiêu đề giống như biến tĩnh trong từng tệp nguồn riêng lẻ.

Kể từ khi tuyên bố một biến static cách này có nghĩa là liên kết nội bộ, tất cả các đơn vị dịch #include ing tập tin tiêu đề của bạn được riêng, cá nhân biến của nó (mà không phải là có thể nhìn thấy bên ngoài đơn vị dịch của bạn). Điều này thường không phải là những gì bạn muốn.

Tôi muốn biết sự khác biệt giữa các biến tĩnh trong tệp tiêu đề so với khai báo trong lớp học là gì.

Trong tuyên bố lớp học, static có nghĩa là tất cả các phiên bản của lớp chia sẻ biến thành viên này; tức là, bạn có thể có hàng trăm đối tượng thuộc loại này, nhưng bất cứ khi nào một trong các đối tượng này đề cập đến biến số static (hoặc "lớp"), nó có cùng giá trị cho tất cả các đối tượng. Bạn có thể nghĩ về nó như là một "lớp toàn cầu".

Biến tĩnh nói chung cũng được khởi tạo trong tệp .cpp khi được khai báo trong lớp phải không?

Vâng, một đơn vị (và chỉ một) dịch phải khởi tạo các biến lớp.

Vậy điều đó có nghĩa là phạm vi biến tĩnh được giới hạn trong 2 đơn vị biên dịch?

Như tôi đã nói:

  • Một tiêu đề không phải là một đơn vị biên soạn,
  • static có nghĩa mọi thứ hoàn toàn khác nhau tùy thuộc vào ngữ cảnh.

Phạm vi giới hạn cho đơn vị dịch thuật. Lớp static nghĩa là toàn cầu đối với tất cả các phiên bản.

Tôi hy vọng điều này sẽ hữu ích.

PS: Kiểm tra đoạn cuối của câu trả lời của Chubsdad, về cách bạn không nên sử dụng static trong C++ để chỉ ra liên kết nội bộ, nhưng không gian tên ẩn danh. (Vì anh ấy đúng .--))

+6

"tĩnh có nghĩa là hoàn toàn khác nhau tùy thuộc vào ngữ cảnh." -> nguồn gốc của sự nhầm lẫn nhất về nó. Suy nghĩ "không thêm từ khóa" này thực sự gây phiền toái: ( –

+0

@Matthieu M. Phụ thuộc vào quan điểm của bạn. Để duy trì tính tương thích giữa C và C++, nó rất có lợi. Tôi thừa nhận, rằng họ đã quá tải nó một chút với ' static'. – DevSolar

+0

Tôi biết rằng khả năng tương thích là cần thiết, nếu không ngôn ngữ sẽ không được phổ biến, tuy nhiên họ có thể đã sử dụng một từ khóa mới cho ý nghĩa C++, họ có thể làm cho nó "không từ khóa" bên ngoài một lớp/Tôi rất vui vì họ đã giới thiệu từ khóa 'nullptr' trong C++ 0x –

38

biến tĩnh trong một tập tin tiêu đề:

nói 'common.h'

static int zzz; 

Biến này 'zzz' đã liên kết nội bộ (biến này cũng không thể được truy cập trong đơn vị dịch khác). Mỗi đơn vị dịch bao gồm 'common.h' có đối tượng duy nhất của riêng nó là tên 'zzz'.

biến tĩnh trong một lớp học:

biến tĩnh trong một lớp học không phải là một phần của subobject của lớp. Chỉ có một bản sao của một thành viên dữ liệu tĩnh được chia sẻ bởi tất cả các đối tượng của lớp.

$ 9.4.2/6 - "dữ liệu tĩnh thành viên của một lớp trong phạm vi không gian tên có bên ngoài liên kết lớp địa phương (3,5) .Bạn sẽ không có các thành viên dữ liệu tĩnh."

Vì vậy, chúng ta hãy nói 'myclass.h'

struct myclass{ 
    static int zzz;  // this is only a declaration 
}; 

myclass.cpp

#include "myclass.h" 

int myclass::zzz = 0   // this is a definition, 
           // should be done once and only once 

"hisclass.cpp"

#include "myclass.h" 

void f(){myclass::zzz = 2;} // myclass::zzz is always the same in any 
           // translation unit 

"ourclass.cpp"

#include "myclass.h" 
void g(){myclass::zzz = 2;} // myclass::zzz is always the same in any 
           // translation unit 

Vì vậy, thành viên tĩnh lớp không chỉ giới hạn trong 2 đơn vị dịch thuật. Chúng chỉ cần được xác định một lần trong bất kỳ một đơn vị dịch thuật nào.

Lưu ý: sử dụng 'tĩnh' tuyên bố tập tin phạm vi biến bị phản đối và namespace giấu tên là một ưu thay thế

+1

cảm ơn bạn rất nhiều vì đã có câu trả lời hay. – brett

+1

"Mỗi tệp bao gồm" ... hoàn toàn không chính xác, thấy rằng các tệp tiêu đề có thể bao gồm các tệp tiêu đề khác. Tốt hơn để gắn bó với cụm từ * đơn vị biên soạn * hoặc * đơn vị dịch *. –

+3

và +1 để chỉ ra rằng các không gian tên ẩn danh thay thế bộ sửa đổi 'tĩnh' cho các biến toàn cục. –

12

Một biến tĩnh khai báo trong một tập tin tiêu đề bên ngoài của lớp sẽ file-scoped trong mọi tệp .c bao gồm tiêu đề. Điều đó có nghĩa là bản sao riêng biệt của một biến có cùng tên có thể truy cập được trong mỗi tệp .c nơi bạn bao gồm tệp tiêu đề.

Biến lớp tĩnh mặt khác là class-scoped và biến tĩnh tương tự có sẵn cho mọi đơn vị biên dịch bao gồm tiêu đề chứa lớp có biến tĩnh.