2013-07-08 23 views
7

Trong chương trình sau "Here" được in:C++ biến tĩnh của lớp unreferenced

#include <iostream> 
class Base 
{ 
    static bool temp; 
    static bool initTemp() 
    {std::cout<<"Here\n";return true;} 
}; 

bool Base::temp = Base::initTemp(); 

class Derived : public Base 
{}; 

int main() {int a;std::cin>>a;} 

Trong chương trình sau "Ở đây" không được in:

#include <iostream> 
template <class T> 
class Base 
{ 
    static bool temp; 
    static bool initTemp() 
    {std::cout<<"Here\n";return true;} 
}; 

template <class T> 
bool Base<T>::temp = Base<T>::initTemp(); 

class Derived : public Base<int> 
{}; 

int main() {int a;std::cin>>a;} 

Trong cả hai trường hợp cơ sở không bao giờ được tham chiếu. Sự khác biệt duy nhất là trong trường hợp thứ hai nó là một lớp mẫu. Bất cứ ai có thể giải thích cho tôi tại sao hành vi này xảy ra. Tôi đang sử dụng VS 2012.

+2

'void main()' không hợp pháp C++. Nên là 'int main()'. –

+0

Trong ví dụ thứ hai, "Ở đây" được in nếu bạn nhanh chóng khởi tạo thành viên tĩnh: 'template bool Base :: temp;' – willj

Trả lời

6

Trong cả hai trường hợp Cơ sở không bao giờ được tham chiếu.

Và đó chính xác là lý do tại sao bạn không thấy nội dung nào được in ra đầu ra tiêu chuẩn.

Định nghĩa của thành viên dữ liệu tĩnh của mẫu lớp không được khởi tạo trừ khi bạn sử dụng thành viên dữ liệu đó; giống như các hàm thành viên, các định nghĩa của các thành viên dữ liệu tĩnh của một mẫu lớp được khởi tạo theo yêu cầu.

này được quy định tại khoản 14.7.1/1 của C++ 11 Tiêu chuẩn:

[...] Các instantiation tiềm ẩn của một lớp mẫu chuyên môn làm cho tiềm ẩn instantiation của tờ khai, nhưng không phải của các định nghĩa hoặc đối số mặc định, của các hàm thành viên lớp, các lớp thành viên, liệt kê thành viên phạm vi, thành viên dữ liệu tĩnh và các mẫu thành viên. [...]

Vì mã khách hàng của bạn không bao giờ đề cập đến Base<>::temp, bạn không cần phải tạo và khởi tạo nó.


Là một mặt lưu ý, chữ ký này:

void main() 

Không phải là hợp lệ (tiêu chuẩn) C++. Nếu bạn muốn viết mã di động, kiểu trả về là main() phải luôn là int.

+0

Nhưng mã chứa 'class Derived: Base ' ... (tại sao) không tính như instantiation? –

+0

Tôi đã chỉnh sửa bài đăng để nó sử dụng int. Có cách nào để khởi tạo lớp bằng cách kế thừa từ lớp đó không? tức là có cách nào để tự động khởi tạo tạm thời cho nhiều loại có nguồn gốc khác nhau mà không cần phải viết mẫu <> bool Base :: temp = Base :: initTemp(); –

+0

@KonradRudolph: "* Sự khởi tạo ngầm của một chuyên biệt về mẫu lớp gây ra sự hiển thị rõ ràng của các khai báo, nhưng không phải của các định nghĩa hoặc đối số mặc định, của các hàm thành viên lớp học, các lớp thành viên, liệt kê thành viên phạm vi, thành viên dữ liệu tĩnh và mẫu thành viên * "(14.7.1/1) –

-3

Bạn không thể tạo biến của lớp không xác định, mà bạn dường như làm với dòng:

template <class T> 
bool Base<T>::temp = Base<T>::initTemp(); 

Bạn không thể phân bổ biến kiểu không xác định. Những gì bạn cần là viết một cái gì đó như:

Base<int>::temp = value; 

nguyên nhân sẽ có biến khác nhau được phân bổ cho từng loại cung cấp, vì vậy bạn không thể có biến tĩnh chung cho một lớp học mẫu. Thay vào đó, bạn sẽ có biến riêng cho từng loại mà bạn khởi tạo mẫu của mình.

Để downvoters ở đây là hoàn toàn ví dụ:

#include <iostream> 

template<class T> 
class X 
{ 
public: 
    static int v; 
}; 

template<class T> 
int X<T>::v = 0; 

int main() 
{ 
    X<int>::v = 3; 
    X<char>::v = 2; 

    using namespace std; 
    cout << X<char>::v << endl << X<int>::v; 
} 

It in 2 3 có nghĩa là bạn không thể có biến duy nhất cho tất cả các lớp học bạn sẽ nhanh chóng mẫu của bạn.

+1

Bạn hoàn toàn có thể. –

+0

Tôi nghĩ Bogolt có ý nghĩa gì đối với mỗi phiên bản X khác nhau, bạn sẽ có một giá trị khác nhau của v. Điều đó đúng nhưng tôi muốn có giá trị khác nhau của v cho mỗi instantiation. Để chia sẻ cùng một biến tĩnh giữa tất cả các phiên bản X nên kế thừa từ một số lớp cơ sở không có mẫu chứa v. –

+0

Ví dụ mã của bạn thực sự cho thấy rằng bạn * có thể làm chính xác những gì bạn yêu cầu mà bạn không thể làm. –

2

Trong trường hợp đầu tiên, bạn không nhanh chóng Base, nhưng bạn gọi hàm tĩnh:

bool Base::temp = Base::initTemp(); 

Trong trường hợp thứ hai, bạn không bao giờ nhanh chóng template:

template <class T> 
bool Base<T>::temp = Base<T>::initTemp(); 

Bạn có thể mô tả rõ ràng mẫu lớp học Base, như:

template class Base<int>; 

Và sau đó bạn sẽ thấy "Ở đây" được in.

+0

OK thật tuyệt, tôi không biết rằng việc chuyển tiếp một lớp mẫu sẽ khởi tạo nó. –

+1

@ BenjyKessler: Đó không phải là tuyên bố về phía trước, đó là một cách diễn đạt rõ ràng –

+0

@BenjyKessler: lol, vâng, đã chỉnh sửa nhận xét. Não tôi đang ngủ –