2016-10-07 17 views
5

Mã của tôi là rất lớn, nhưng tôi sẽ cố gắng giảm thiểu nó ở đây là tốt nhất có thể.Tại sao biến số tĩnh xác định trên toàn cầu được đặt lại?

Về cơ bản, tôi muốn xác định chuỗi được sửa đổi chỉ trong một địa điểm (chính của tôi) và sau đó được đọc trong toàn bộ chương trình của tôi.

Định nghĩa của tôi.h được bao gồm ở mọi nơi để tôi xác định.

static std::string MAINLOG = "RANDOMNES"; 

Trong chức năng chính của tôi, tôi làm:

for (int i = 0; i < files.size(); i++){ 

    // Do stuff  

    prepDbugDir(); // This sets MAINLOG to "CORRECT_VALUE" 

    std::cout << "Before " << MAINLOG << std::endl; 

    // Call a class function whose includes include my defines.h 

    std::cout << "After " << MAINLOG << std::endl; 


} 

Và in ra của tập tin của tôi là

Before CORRECT_VALUE 
RANDOMNESS 
After CORRECT_VALUE 

Vì vậy, câu hỏi của tôi là lý do tại sao và làm thế nào tôi có thể nhận được giá trị là được duy trì bên trong lớp học của tôi.

+0

Bạn đã chia nhỏ thông tin chương trình của mình một số * .a hoặc * .o? có vẻ như là do bạn chia chương trình thành nhiều tệp đối tượng, có một số bản sao của MAINLOG tồn tại. –

+0

Khi biên dịch, có. Nếu đó là vấn đề, có cách nào xung quanh vấn đề này không? – aarelovich

+1

Thử đặt khai báo MAINLOG trong tiêu đề và định nghĩa chỉ một lần trong một tệp .cpp đơn bao gồm tiêu đề (có lẽ là define.cpp). – Baldrick

Trả lời

6

Mọi đơn vị dịch (tệp .c hoặc .cpp, về cơ bản) bao gồm defines.h sẽ có bản sao biến riêng.

Tôi tin rằng tuyên bố toàn cầu extern trong tiêu đề

extern std::string MAINLOG; 

và sau đó xác định nó như là một biến toàn cục không tĩnh trong bất kỳ một của .c hoặc cpp file

std::string MAINLOG = "RANDOMNES"; 

sẽ giải quyết vấn đề. Nhưng đó là phong cách mã hóa nghèo nàn, IMO. Cách C++ sẽ ít nhất là một lớp đơn.

tôi không thể đưa ra tên có ý nghĩa mà không biết bối cảnh, nhưng ý tưởng là như sau:

mainlog.h

class Mainlog { 
    Mainlog() = default; // Private default constructor 

    static Mainlog& instance(); 

public: 
    static const std::string& get() { 
     return instance().value; 
    } 

    static void set(const std::string& newValue) { 
     instance().value = newValue; 
    } 

private: 
    std::string value {"RANDOMNESS"}; 
}; 

mainlog.cpp (không đặt này trong một tiêu đề!)

Mainlog& Mainlog::instance() { 
     static Mainlog mainlog; 
     return mainlog; 
    } 
+1

đồng ý lớp singleton tốt hơn thuộc tính tĩnh toàn cục –

+0

Tôi có một lớp main.cpp và sau đó là các lớp của tôi. Tôi khai báo đăng nhập chính là bên ngoài trong định nghĩa của tôi và trong chính của tôi (bên trong main.cpp của tôi), tôi đặt giá trị của nó. Khi tôi làm điều này tôi nhận được lỗi linker: undefined tham chiếu đến 'MAINLOG 'nơi mà tôi thực sự muốn đọc nó. – aarelovich

+1

Bạn có thể cho tôi một ví dụ về một lớp singleton không? – aarelovich

3

Đây là những gì tôi muốn giới thiệu.

Trong defines.h:

const std::string& mainlog(); 

Trong main.cpp:

const std::string& mainlog() { 
    static std::string MAINLOG = "CORRECT_VALUE"; 
    return MAINLOG; 
} 
+0

Không thể sử dụng một const vì giá trị sẽ thay đổi nhiều lần trong khi chạy. – aarelovich

+0

Nhưng bạn muốn thay đổi nó trong chính. Bạn không muốn bất kỳ ai khác có thể thay đổi nó, vì vậy họ có thể thấy một tham chiếu const, nhưng không thể sửa đổi nó. Đây cũng là singleton đầu tiên được đăng. Nhưng bạn cũng có thể trả về một bản sao của MAINLOG (chỉ std :: string) –

1

Bởi vì bạn đặt nó trong tập tin defines.h của bạn, mà bạn sau đó bao gồm trong các tập tin cpp của bạn, mỗi Tệp .cpp có thể hiện riêng của chuỗi, chỉ hiển thị bên trong tệp .cpp đó. static tạo biến chỉ hiển thị bên trong .cpp nơi nó được khai báo.

Thay đổi tĩnh để extern trong defines.h của bạn, như thế này:

extern std::string MAINLOG;

Sau đó, trong một và chỉ một trong các chiến.tệp cpp, hãy thêm điều này:

std :: string MAINLOG = "RANDOMNES";

Điều đó sẽ cung cấp cho bạn hành vi bạn mong đợi, nhưng các biến toàn cục như thế này là ý tưởng BAD.

+0

Bạn không muốn trình khởi tạo trên mục nhập trong tệp tiêu đề. –

+0

Đó là chính xác. Tôi sẽ sửa nó. (Niềm vui khi cắt và dán) –

0

Khi bạn xác định biến có bộ nhớ tĩnh trong tiêu đề, mỗi bản dịch sẽ nhận biến duy nhất của riêng nó theo tên đó.

Một sửa chữa đơn giản, nếu bạn không muốn đi theo con đường singleton, là tuyên bố

extern const std::string& MAINLOG; 

trong tiêu đề của bạn, và sau đó là tập tin chính xác

std::string MAINLOG_INTERNAL = "RANDOMNESS"; 
const std::string& MAINLOG = MAINLOG_INTERNAL; 

này sẽ cung cấp bạn một chuỗi có thể ghi có một "view" chỉ đọc trong phần còn lại của chương trình.

Sau đó, bạn có thể

void prepDbugDir() 
{ 
    MAINLOG_INTERNAL = "CORRECTNESS"; 
} 

trong tập tin chính.

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