C ++ nơi khởi tạo const tĩnh


129

Tôi có một lớp học

class foo {
public:
   foo();
   foo( int );
private:
   static const string s;
};

Đâu là nơi tốt nhất để khởi tạo chuỗi strong tệp nguồn?

Câu trả lời:


178

Bất cứ nơi nào trong một đơn vị biên dịch (thường là tệp .cpp) sẽ làm:

foo.h

class foo {
    static const string s; // Can never be initialized here.
    static const char* cs; // Same with C strings.

    static const int i = 3; // Integral types can be initialized here (*)...
    static const int j; //     ... OR in cpp.
};

foo.cpp

#include "foo.h"
const string foo::s = "foo string";
const char* foo::cs = "foo C string";
// No definition for i. (*)
const int foo::j = 4;

(*) Theo các tiêu chuẩn bạn phải xác định ibên ngoài định nghĩa lớp (giống như j) nếu nó được sử dụng trong mã khác với chỉ các biểu thức hằng tích phân. Xem bình luận của David dưới đây để biết chi tiết.


27
Tôi đã nâng cấp, nhưng sau khi xem xét tiêu chuẩn, có một lỗi trong mã của bạn: iphải được xác định trong cpp. §9.4.2 / 4 Nếu một thành viên dữ liệu tĩnh thuộc kiểu liệt kê const hoặc tích phân const, khai báo của nó trong định nghĩa lớp có thể chỉ định một bộ khởi tạo hằng sẽ là biểu thức hằng tích phân (5.19). Trong trường hợp đó, thành viên có thể xuất hiện trong các biểu thức hằng số tích phân. Thành viên vẫn sẽ được xác định trong phạm vi không gian tên nếu nó được sử dụng trong chương trình và định nghĩa phạm vi không gian tên sẽ không chứa bộ khởi tạo.
David Rodríguez - dribeas

3
Dựa trên báo giá của bạn từ các tiêu chuẩn, có vẻ như isẽ phải được xác định duy nhất nếu nó được sử dụng ở một nơi khác hơn trong các biểu thức hằng số tích phân, phải không? Trong trường hợp này, bạn không thể nói rằng có lỗi vì không có đủ ngữ cảnh để chắc chắn - hoặc nói một cách nghiêm túc ví dụ trên là chính xác nếu không có mã nào khác. Bây giờ tôi đánh giá cao nhận xét của bạn (+1), tôi vẫn đang tự học mọi thứ! Vì vậy, tôi sẽ cố gắng và làm rõ điểm đó trong câu trả lời, xin vui lòng cho tôi biết nếu nó tốt hơn ...
squelart

@squelart Xin lỗi nếu tôi nghe có vẻ ngu ngốc nhưng một ví dụ về câu lệnh khác với biểu thức hằng số tích phân sẽ là?
Saksham

3
@Saksham Ví dụ: gọi một hàm, ví dụ: int f() { return 42; } class foo { static const int i = f(); /* Error! */ }Lưu ý rằng C ++ 11 cho phép gọi các hàm 'constexpr':constexpr int f() { return 42; } class foo { static const int i = f(); /* Ok */ }
squelart

@squelart Tôi đọc văn bản sao cho định nghĩa phải được cung cấp nếu thành viên được sử dụng hoàn toàn - từ ngữ trong tiêu chuẩn không giới hạn yêu cầu đó đối với các biểu thức hằng tích phân.
VladLosev

12

Các thành viên tĩnh cần được khởi tạo trong một đơn vị dịch .cpp ở phạm vi tệp hoặc trong không gian tên thích hợp:

const string foo::s( "my foo");

11

Trong một đơn vị dịch trong cùng một không gian tên, thường ở trên cùng:

// foo.h
struct foo
{
    static const std::string s;
};

// foo.cpp
const std::string foo::s = "thingadongdong"; // this is where it lives

// bar.h
namespace baz
{
    struct bar
    {
        static const float f;
    };
}

// bar.cpp
namespace baz
{
    const float bar::f = 3.1415926535;
}

8

Kể từ C ++ 17, bộ xác định nội tuyến cũng áp dụng cho các biến. Bây giờ bạn có thể định nghĩa các biến thành viên tĩnh trong định nghĩa lớp:

#include <string>

class foo {
public:
   foo();
   foo( int );
private:
   inline static const std::string s { "foo" };
};

1

Chỉ các giá trị tích phân (ví dụ static const int ARRAYSIZE:) được khởi tạo trong tệp tiêu đề vì chúng thường được sử dụng trong tiêu đề lớp để xác định một cái gì đó như kích thước của một mảng. Các giá trị không tách rời được khởi tạo trong tệp thực hiện.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.