2012-07-13 23 views
5

Tôi nghĩ rằng tôi hvae một sự hiểu lầm cơ bản của không gian tên và/hoặc biến tĩnh. Nhưng tôi đã cố gắng mã kiểm tra này (gõ bằng tay, tha thứ cho lỗi chính tả)Làm thế nào để làm việc với biến trong không gian tên

test.h:

namespace test{ 
    static int testNum=5; 
    void setNum(int value); 
} 

main.cpp:

#include <test.h> 

int test::setNum(int value){ 
    testNum=value; 
} 

int main(){ 
    test::setNum(9); 
    cout<<test::testNum; 
} 

khi tôi chạy này, tôi nhận được giá trị 5 , không phải 9 như tôi mong đợi. Dường như dường như tôi có hai trường hợp của biến testNum, nhưng điều đó dường như ngược lại với những gì tĩnh nên làm. Tôi đoán tôi đã phạm sai lầm khi giả định rằng các tính năng này giống hệt với cách thức phân tích java của chúng bằng cách nào đó ...

Tôi cũng nhận được thông báo rằng testNum được khai báo nhiều lần nếu tôi xóa tĩnh khỏi khai báo của mình testNum, ai đó có thể giải thích lý do tại sao đó là trường hợp?

Cảm ơn bạn

+1

Bạn có biết cách '# include' hoạt động không? Nó sao chép-dán nội dung của tập tin được chỉ định. Và định nghĩa 'setNum' có thực sự trong' main.cpp' không? – Xeo

+0

Tôi không hiển thị nó, nhưng tôi có tiêu chuẩn ifNDEF DEF trong .h. bên cạnh đó, vì tôi chỉ bao gồm nó * một lần * trong toàn bộ chương trình, nó vẫn không phải là vấn đề đúng không? – dsollen

+0

Bạn có sử dụng 'sử dụng kiểm tra không gian tên' không? –

Trả lời

14

Trước tiên, sự hiểu lầm của bạn có không có gì để thực hiện với không gian tên, chỉ khoảng static. Đối với phần còn lại của câu trả lời này tôi sẽ chỉ đơn giản là testNum bởi vì thực tế nó trong một không gian tên là không liên quan.

Tôi cũng giả định bạn đã một file, có lẽ gọi là test.cpp, mà còn bao gồm test.h và xác định setNum chức năng.

Khi biến hoặc hàm ở phạm vi không gian tên (nghĩa là không phải là thành viên của lớp hoặc cục bộ đối với hàm) được khai báo static nghĩa là tên của thực thể nằm trong tệp đó. Chính thức nó có "liên kết nội bộ", có nghĩa là nó không thể được gọi bằng tên hoặc liên kết đến từ các tệp khác (nó có thể được gián tiếp gọi thông qua một con trỏ hoặc bằng cách chuyển nó như một đối số cho một hàm khác.) tập tin xác định static int testNum thì mỗi tệp có biến nội bộ riêng với tên đó, khác biệt với testNum trong mỗi tệp khác (trên thực tế, một tệp có thể có static int testnum và một tệp khác có thể có static double testnum và một tệp khác là static char* testNum. tệp.) Nếu bạn đặt định nghĩa như vậy trong tiêu đề thì mọi tệp có tiêu đề có testNum riêng.

Vì vậy, với static trên biến của bạn trong một tiêu đề bạn có một biến khác nhau gọi testNum trong mỗi tập tin có chứa test.h. Điều đó có nghĩa là nếu bạn đặt testNum trong một tệp và gọi hàm trong một tệp khác sử dụng testNum, nó đề cập đến một biến số khác nhau, mà chỉ xảy ra có cùng tên.

Do đó, việc khai báo các biến số static không phải trong tiêu đề hầu như luôn luôn sai.

Nếu không có static, bạn sẽ có định nghĩa về biến số testNum trong mỗi tệp bao gồm test.h, không được phép: mọi thực thể phải được xác định một lần và một lần duy nhất trong chương trình của bạn. Cách giải quyết đó là tuyên bố biến trong tiêu đề, nhưng không phải xác định nó, mà bạn làm bằng cách nói với trình biên dịch biến là extern:

extern int testNum; // N.B. no "= 1" here 

Điều đó nói với trình biên dịch có một biến với "liên kết bên ngoài" được gọi là testNum, vì vậy khi mã đề cập đến testNum, nó sẽ luôn có nghĩa là cùng một biến (không phải tên nào đó với linakge nội bộ là một thực thể khác trong mỗi tệp.) Sau khi khai báo biến số extern, bạn có trách nhiệm đảm bảo chính xác là một định nghĩa được cung cấp ở đâu đó trong chương trình, do đó, trong chính xác một tệp (tức là không có tiêu đề được bao gồm trong nhiều tệp), bạn xác định nó:

int testNum = 1; 
+0

Cảm ơn bạn, điều đó giải thích vấn đề của tôi. Khi tôi nghĩ rằng tôi đã đưa ra giả định sai về cách làm việc tĩnh từ sự phát triển java của tôi, mặc dù tôi đã xem xét tĩnh trước và nghĩ rằng c + + tĩnh sẽ giống nhau ... một trong những tình huống mà bạn thấy câu trả lời mà bạn mong đợi. Tôi thực sự muốn chương trình thực sự của tôi có giá trị tĩnh mặc định cho một cái gì đó an toàn không có vấn đề gì (ngay cả khi ai đó đi và thay đổi main.h của tôi) để đảm bảo tôi không có chức năng lẻ. Có vẻ như nếu extern ngăn cản tôi có được gaurentee rằng nó bắt đầu với một giá trị mặc định hợp lệ. bất kỳ cách nào để đảm bảo điều đó? – dsollen

+0

'tĩnh' có nghĩa là một vài điều trong C++. Đối với các thành viên _class_ nó tương tự như Java, nhưng bạn không có một thành viên lớp trong chương trình của bạn, bạn có các thành phần không phải là thành viên, không tồn tại trong Java. –

+0

Tôi không có ý kiến ​​gì về ý nghĩa của bạn về extern ngăn chặn giá trị "mặc định" hoặc "mặc định cho một cái gì đó an toàn". Có gì sai với giá trị '= 1' tôi đưa ra trong câu trả lời của tôi? –

3

static tại phạm vi không gian tên là từ khóa sai và không được sử dụng. Nó có nghĩa đơn giản là thực thể được khai báo tĩnh có gắn tên nội bộ; nói cách khác, cùng tên trong các đơn vị dịch thuật khác sẽ tham chiếu cho một thực thể khác và trong trường hợp các định nghĩa biến, sẽ có một biến riêng biệt của biến trong mỗi đơn vị dịch . Nó không ảnh hưởng đến tuổi thọ. (Tất cả các biến số được khai báo hoặc được xác định tại phạm vi không gian tên có tuổi thọ tĩnh.)

static tại phạm vi không gian tên cũng bị phản đối. Không sử dụng nó.

Liên quan đến việc khai báo một biến trong tiêu đề: tiền tố là extern và không phải static. Nếu một biến được khai báo là extern và không có khởi tạo thì khai báo không phải là định nghĩa. Trong số khóa học, trong trường hợp này, bạn phải cung cấp định nghĩa ở đâu đó (trong một tệp nguồn đơn ). Một cái gì đó dọc theo dòng:

extern int testNum = 5; 
int testNum = 5; 
int testNum;   // implicitly initialized with 0. 

EDIT:

Để làm rõ phần nào: có một số nhầm lẫn ở đây giữa cuộc đời và tên ràng buộc:

  • một đối tượng có thời gian sống (tự động, tĩnh hoặc động — hoặc tạm thời hoặc ngoại lệ) và
  • tên được gắn với một thực thể; nếu tên được khai báo là một biến, thực thể là một đối tượng.

Làm không nhầm lẫn từ khóa static với tuổi thọ tĩnh. (Các hàm có thể là static, nhưng các hàm không có thời gian xác định trong C++; chúng chỉ là .)

Quy tắc liên quan đến các hàm này không phải là rất chính thức.Về cơ bản, với liên quan đến cuộc đời:

  • tất cả các biến khai báo ở phạm vi không gian tên có tuổi thọ tĩnh, luôn luôn,
  • biến khai báo ở phạm vi địa phương có ô tô đời trừ chúng được khai báo static, và
  • biến khai báo ở phạm vi lớp có tuổi thọ của đối tượng lớp chứa chúng, trừ khi chúng được khai báo là static. liên quan đến tuổi thọ.

Đối tượng có thời gian tồn tại tĩnh tồn tại đôi khi trước main và trực tiếp cho đến sau khi bạn quay về từ main.

Liên quan đến tên ràng buộc:

  • biến khai báo ở phạm vi không gian tên có ràng buộc, trừ khi chúng được công bố static, trong trường hợp họ có nội tên ràng buộc (nhưng việc sử dụng này static bị phản đối tên bên ngoài) hoặc nếu chúng là const và không được khai báo extern,
  • biến được khai báo ở phạm vi lớp học có gắn kết tên bên ngoài, ngay cả khi chúng được khai báo static
  • biến được khai báo ở phạm vi khối không có ràng buộc.

Cuối cùng, có câu hỏi liệu tuyên bố có phải là định nghĩa hay không. Nếu nó là một định nghĩa, bộ nhớ được cấp phát và đối tượng là (hoặc có thể) được khởi tạo. Nếu nó không phải là một định nghĩa, nó chỉ đơn giản là nói với trình biên dịch rằng có một định nghĩa ở một nơi khác cho thực thể (đối tượng) được khai báo trong khai báo. Nói chung, một khai báo biến là định nghĩa trừ khi nó được khai báo extern và không không có trình khởi tạo.

+0

Cảm ơn bạn đã giải quyết (tôi sẽ đi kiểm tra trong một giây) nhưng đối với sự giác ngộ của riêng tôi, bạn có thể giải thích rõ hơn vấn đề là gì không? Bạn nói rằng tất cả các biến trong một không gian tên là tĩnh, nhưng điều đó vẫn để lại cho tôi tự hỏi tại sao trong ví dụ này mã của tôi sẽ không hoạt động vì tất cả những gì tôi cần là một biến tĩnh. Bạn đang ở đó mà tôi đã kết thúc tuyên bố hai biến tĩnh với cùng một tên mỗi nơi tôi tham khảo testnum? – dsollen

+0

@dsollen Tôi đã chỉnh sửa để thêm một số giải thích. –

1

Bạn có thể muốn chắc chắn rằng mã của bạn thực sự có vấn đề trước khi bạn gửi nó hỏi có chuyện gì vậy;)

sao chép/dán và cố định lỗi chính tả của bạn, và tự đã bao gồm:

#include <iostream> 
using namespace std; 

namespace test{ 
    static int testNum=5; 
    void setNum(int value); 
} 

void test::setNum(int value){ 
    testNum=value; 
} 

int main(){ 
    test::setNum(9); 
    cout<<test::testNum; 
} 

kết quả:

$ ./a.out 
9 

Điều bạn chưa nói là những gì khác trong chương trình của bạn. Nếu bạn có nhiều hơn chỉ main.cpp, và bao gồm test.h của bạn, sau đó mỗi tập tin .cpp sẽ có bản sao riêng của testNum. Nếu bạn muốn họ chia sẻ thì bạn cần tất cả nhưng phải đánh dấu nó là extern.

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