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 và đị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!
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ử! –