2016-01-17 22 views
9

Tôi không hiểu tại sao C++ chỉ cho phép các kiểu tách rời và enum (enum là một kiểu tách rời) được xác định trong một khai báo lớp. Trong khi tất cả các loại khác, bao gồm các loại điểm phao (tức là double và float), phải được xác định bên ngoài khai báo lớp. Rõ ràng phải là một lý do cho điều này, nhưng tôi không thể tìm ra.Tại sao chỉ có thể khởi tạo kiểu tích phân hoặc enum trong một lớp C++?

Mã dụ:

#include <iostream> 

using namespace std; 

struct Node { 

    static const int c = 0; // Legal Definition 
    static const long l = 0l; // Legal Definition 
    static const short s = 0; // Legal Definition 

    static const float f = 0.0f; // Illegal definition 
    static const string S = "Test"; // Illegal definition 

    static const string JOB_TYPE; // Legal declaration 
    static const float f; // Legal declaration 
    static const double d; // Legal declaration 
}; 

const string Node::JOB_TYPE = "Test"; // correct definition 
const float Node::f = 0.0f; // correct definition 
const double Node::d = 0.0; // correct definition 

int main() { 

    cout << Node::c << endl; 
    cout << Node::c << endl; 

    cout << Node::JOB_TYPE << endl; 

    cout << Node::f << endl; 

} 
+0

Bạn sẽ chỉ gặp sự cố nếu bạn đặt cấu trúc 'Node' trong tiêu đề và bạn đưa nó vào 2 tệp. –

+1

Đây là một câu hỏi rất hay - Đã có các tế bào não của tôi ratting vào chủ nhật này. Cảm ơn –

+2

Các quy tắc đặc biệt cho dấu phẩy động thường là do những lo ngại về trình biên dịch chéo, tức là các trình biên dịch chạy trên một hệ thống nhưng tạo mã cho một hệ thống khác. Thật dễ dàng để đối phó với các loại tích phân phù hợp với hệ thống đích; nhận được các chi tiết về các loại dấu phẩy động của một hệ thống khác phức tạp hơn nhiều. –

Trả lời

8

Lý do chính ở đây là loại không thể thiếu (và enum vì bên trong trình biên dịch này trở thành số nguyên của một số loại) có thể được thay thế trivially và sử dụng trực tiếp như hằng số.

Nói cách khác, struct S { static const int x = 42;}, nếu trình biên dịch thấy S::x, nó có thể ngay lập tức thay thế bằng hằng số 42 trong mã được tạo. Tương tự không (luôn luôn) áp dụng cho float và chắc chắn không dành cho các loại nhà xây dựng phụ thuộc như std::string - trình biên dịch không thể cấp phát bộ nhớ cho std::string mà không cần gọi số new (hoặc std::string::allocator). Vì vậy, đối với các hằng số phải được "xây dựng" và/hoặc có các tiêu chí phức tạp hơn về cách chúng có thể được sử dụng (nghĩ về một bộ xử lý không hỗ trợ phần cứng cho các hàm gọi dấu phẩy động để tải và lưu trữ các giá trị dấu chấm động, vv), ngôn ngữ không thể ra lệnh rằng nó nên được phép làm điều đó.

Nếu bạn bao gồm khai báo struct Node với static const std::string S = "test";, bao nhiêu vị trí mà trình biên dịch lưu trữ Node::S trong? Nên sử dụng cái nào, khi nó kết nối ba đơn vị dịch của bạn thành một chương trình - hoặc nó nên sử dụng các chương trình khác nhau? Điều gì xảy ra sau đó nếu bạn const_cast các Node::S và sửa đổi nó? Cái thứ hai giả định rằng bạn có một môi trường mà điều này không gây ra sự cố, điều này hoàn toàn chính đáng, và trong khi đó là hành vi không xác định, tôi không chắc trình biên dịch sẽ làm cho nó trở nên kỳ lạ như sử dụng các giá trị khác nhau trong mỗi đơn vị dịch trường hợp đó ...

Chỉnh sửa: Như đã đề cập trong các nhận xét, C++ 11 cho phép các loại khác được sử dụng theo cách tương tự, vì vậy các hạn chế được thoải mái khi trình biên dịch và công nghệ phần cứng đang được cải thiện. Tôi nghi ngờ bạn sẽ có thể static const std::map<X, Y> a = { ... } tho ', vì đó là một kiểu dữ liệu khá phức tạp để xây dựng ...

+0

"Lý do chính ở đây là các loại tích phân (và enum bởi vì bên trong trình biên dịch này trở thành số nguyên của một số loại) có thể được thay thế trivially và sử dụng trực tiếp như hằng số." cách - có lẽ chúng ta có thể hy vọng rằng quy tắc sẽ được thư giãn để bao gồm những điều này? –

+0

Vâng, vấn đề là các literals cũng có thể là các giá trị dấu phảy động [không chắc chắn có những người khác] hay không, và chúng thường yêu cầu xử lý đặc biệt - đặc biệt là trên phần cứng không có hỗ trợ tích hợp cho dấu phẩy động. –

+1

@ChrisBeck "sẽ được thư giãn" -> "được thư giãn". http://melpon.org/wandbox/permlink/1qxlfeqKMVWoeti7 và thông thường hơn, tất cả các loại chữ, [class.static.data] p3 – dyp

0

Việc khởi tạo std::string yêu cầu một số mã được thực thi trong thời gian chạy.

Việc khởi tạo con trỏ có chuỗi ký tự yêu cầu đặt chuỗi ở đâu đó trong bộ nhớ, cũng trong thời gian chạy.

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