2014-04-04 13 views
8

Vì vậy, chúng ta hãy nói rằng tôi có một tiêu đề như thế này:Tại sao tôi không nên khởi tạo biến tĩnh trong tiêu đề?

#ifndef BASECLASS_H 
#define BASECLASS_H 

class BaseClass 
{ 
    public: 
     static int getX(){return x;} 
    private: 
     static int x; 
}; 

int BaseClass::x = 10; 

#endif 

Tôi đã nghe nói nhiều lần rằng tôi không nên khởi biến tĩnh bên trong một tiêu đề, mà là trong cpp. Nhưng vì có những người bảo vệ, nên chỉ có một bản sao của BaseClass :: x. Vì vậy, tôi không hiểu tại sao tôi nên đặt

int BaseClass::x = 10; 

in cpp. Cảm ơn.

+0

Câu hỏi đặt câu hỏi và câu trả lời ở đây vượt trội so với những câu hỏi được đề cử! –

Trả lời

9

Nếu bạn làm điều đó trong tiêu đề, bạn sẽ nhận được nhiều lỗi định nghĩa ngay sau khi bạn đưa nó vào từ nhiều tệp CPP. Bạn thực sự yêu cầu trình biên dịch hai điều khi bạn khai báo

int BaseClass::x = 10; 

Trước tiên, bạn đang xác định biểu tượng BaseClass :: x; thứ hai bạn đang nói với nó rằng bạn muốn nó có giá trị ban đầu là 10. Theo điều này chỉ có thể xảy ra một lần trong chương trình của bạn.

+0

Tôi nghĩ rằng tôi bắt đầu nhận được ý tưởng, nhưng có cách nào để chứng minh điều đó không? Có phải tôi cần viết hai chương trình khác nhau, trong đó có BaseClass và chạy chúng một cách đồng thời không? – user3496846

+2

@ user3496846 không, bạn chỉ cần có một chương trình bao gồm (ít nhất) hai tệp cpp, cả hai đều bao gồm tiêu đề của bạn. –

2

Vì nếu bạn khởi tạo nó trong tiêu đề, có khả năng nó sẽ được xác định ở nhiều vị trí nếu bạn bao gồm tiêu đề nhiều lần. Điều này sẽ dẫn đến lỗi liên kết

4

Các nhân viên bảo vệ không ngăn nhiều bản sao trong nhiều tệp nguồn. Chúng chỉ ngăn chặn nhiều bản sao trong một tệp nguồn.

Bạn sẽ vi phạm quy tắc một định nghĩa nếu bạn có nhiều tệp nguồn #include "base_class.h".

4

Có thể dễ hiểu hơn nếu bạn nghĩ về những gì mà bộ tiền xử lý thực sự làm: Nó sao chép nội dung của tất cả các tệp tiêu đề đi kèm vào tệp cpp và chuyển nó tới trình biên dịch.

Bây giờ giả sử bạn có:

// In a.cpp 
#include <baseclass.h> 

// more code 

// In b.cpp 
#include <baseclass.h> 

// more code 

Sau khi tiền xử lý mở rộng bao gồm cả các file sẽ chứa:

int BaseClass::x = 10; 

Bây giờ càng sớm càng cả hai tập tin đối tượng được truyền cho các mối liên kết, nó sẽ thấy biểu tượng BaseClass::x hai lần - đây là lỗi.

Bây giờ, để làm cho nó thậm chí còn rõ ràng hơn, hãy tưởng tượng bạn sẽ đặt điều này trong một tập tin tiêu đề:

int aGlobalVariable = 10; 

Và sau đó đưa nó vào trong hai tập tin cpp khác nhau, mà cả hai nên được liên kết thành một thực thi. Nó thực sự không khác với ví dụ của bạn, nếu nhìn từ quan điểm của nhà liên kết.

Tại sao đây không phải là vấn đề với khai báo lớp?

Có sự khác biệt giữa các tờ khai định nghĩa. Chỉ cái sau sẽ gây ra vấn đề. Ví dụ., Tất cả những điều sau đây là tờ khai:

  • extern int a;
  • void foo(int a);
  • class Foo { int bar(); };

Trong khi đây là những định nghĩa:

  • int a;
  • int b = 10;
  • void foo(int a) { /*..*/ }
  • int Foo::bar() { /*...*/ }

Chừng nào có một (và chỉ một) định nghĩa, bạn có thể có nhiều tuyên bố như bạn muốn, và các mối liên kết sẽ đảm bảo tất cả họ đều tham khảo cùng một chức năng hoặc vị trí bộ nhớ.

Bây giờ còn các lớp học thì sao? Các lớp chỉ có thể được khai báo, trong khi các hàm thành viên của chúng và các thành viên tĩnh phải được xác định. Một lần nữa, mỗi định nghĩa chỉ có thể tồn tại một lần.

Chức năng thành viên và thành viên tĩnh thực sự chỉ tồn tại một lần trong không gian địa chỉ của chương trình, trong khi các thành viên thông thường (biến mẫu) tồn tại cho từng đối tượng của lớp.

Quay trở lại vấn đề cụ thể của bạn: các thành viên tĩnh về cơ bản chỉ là các biến toàn cục, nhưng phạm vi đến tên của lớp.

Hy vọng điều này sẽ xóa mọi thứ cho bạn!

+0

Nhưng bên cạnh #include "baseClass.h", trình liên kết cũng sẽ bao gồm định nghĩa kép của chính lớp đó, điều này cũng sẽ gây ra sự cố không? Xin lỗi, nó có thể mất thời gian cho tôi để hiểu ... – user3496846

+0

Không, bởi vì nó chỉ là một lớp * khai báo *. Tôi sẽ thêm một chút về điều đó vào câu trả lời của tôi –

+0

OK, cảm ơn bạn rất nhiều vì câu trả lời mô tả như vậy, tôi nghĩ rằng tôi bắt đầu nhận được ý tưởng :) – user3496846

Các vấn đề liên quan