2012-11-27 23 views
12

Thông thường khi bạn có một biến thành viên tin liên tục trong lớp học của bạn, mà chỉ có một getter nhưng không setter, nó sẽ giống như thế này:C++ xác định một biến thành viên liên tục bên trong constructor lớp

// Example.h 
class Example { 
    public: 
     Example(const int value); 
     const int getValue() const; 
    private: 
     const int m_value; 
}; 


// Example.cpp 
#include "Example.h" 

Example::Example(const int value) 
: m_value(value) 
{ 
} 

const int Example::getValue() const 
{ 
    return m_value; 
} 

Bây giờ những gì Tôi đang cố gắng làm, có một biến thành viên int không đổi như thế, nhưng thay vì định nghĩa nó trong phần khởi tạo như vậy: : m_value(value) Tôi cần phải lấy một đối tượng khác - tôi sẽ sử dụng một vectơ trong ví dụ này - như tham số của hàm tạo và đặt m_value dựa trên đối tượng tham số. Trong trường hợp này, tôi sẽ cố gắng làm kích thước + 1 vector, nếu kích thước là trên 0. Vì vậy, đây là những gì tôi đã làm:

Example::Example(std::vector<Example*> myVec) 
{ 
    if (myVec.size()) { 
     m_value = myVec.size() + 1; 
    } 
    else { 
     m_value = -1; 
    } 
} 

Nhưng tôi nhận được một lỗi uninitialized member 'Example::m_value' with 'const' type 'const int' và nếu tôi init m_value bên trong Khởi tạo phần, tôi nhận được lỗi assignment of read-only data-member 'Example::m_value' mà tất cả làm cho tinh thần với tôi, tôi là nghĩa vụ phải có được những sai sót, nhưng làm thế nào tôi có thể đi xung quanh họ?

Chỉnh sửa: Chỉ cách tôi có thể chỉnh sửa m_value là bên trong chính đối tượng (vì m_value là riêng tư). Chỉ có getter sẽ hạn chế tôi đặt m_value thành bất kỳ thứ gì ngoài những gì được thiết lập trong hàm tạo. Tôi có được lợi ích gì khi có int liên tục như một biến thành viên?

+1

': m_value (! MyVec.empty()? MyVec.size() + 1: -1)'? – hmjd

+0

tại sao nó phải là 'const'? – Nim

+0

Đối với cập nhật của bạn - không, không có lợi ích mà tôi có thể nhìn thấy ... – Nim

Trả lời

22

Sử dụng hàm thành viên tĩnh để tính toán kết quả bạn cần và gọi hàm đó trong danh sách khởi tạo. Như thế này:

// Example.h 
class Example { 
    public: 
     Example(const int value); 
     Example::Example(std::vector<Example*> myVec); 

     const int getValue() const; 
    private: 
     const int m_value; 

     static int compute_m_value(::std::vector<Example*> &myVec); 
}; 

// Example.cpp 
#include "Example.h" 

Example::Example(const int value) 
: m_value(value) 
{ 
} 

Example::Example(std::vector<Example*> myVec) 
: m_value(compute_m_value(myVec) 
{ 
} 

const int Example::getValue() const 
{ 
    return m_value; 
} 

int Example::compute_m_value(::std::vector<Example*> &myVec) 
{ 
    if (myVec.size()) { 
     return myVec.size() + 1; 
    } 
    else { 
     return -1; 
    } 
} 

Trong trường hợp đặc biệt này, các chức năng như vậy là rất đơn giản bạn chỉ có thể sử dụng toán tử tam phân (aka : m_value(myVec.size() > 0 ? myVec.size() + 1 : -1) trong constructor để trực tiếp tính toán giá trị lúc khởi tạo. Điều này trông giống như một ví dụ, vì vậy tôi đã cho bạn một phương pháp rất chung về giải quyết vấn đề, ngay cả khi phương pháp tính toán câu trả lời bạn cần có thể rất phức tạp.

Vấn đề chung là các biến thành viên không đổi (và các biến thành viên là tham chiếu quá BTW) phải được khởi tạo trong danh sách khởi tạo. Nhưng khởi tạo có thể là biểu thức, có nghĩa là chúng có thể gọi hàm. Vì mã khởi tạo này khá cụ thể đối với lớp, nên nó là một hàm riêng (hoặc có thể được bảo vệ) cho lớp đó. Nhưng, vì nó được gọi để tạo ra một giá trị trước khi lớp được xây dựng nên nó không thể phụ thuộc vào một cá thể lớp tồn tại, do đó không có con trỏ this. Điều đó có nghĩa là nó cần phải là một hàm thành viên tĩnh.

+1

+1 để giải quyết vấn đề chung và giải thích rõ ràng. – undu

5

Đầu tiên, biến là được xác định trong định nghĩa lớp, không phải trong hàm tạo. Đó là được khởi tạo trong hàm tạo.

Thứ hai, cách để làm điều đó là giống như những gì nhà xây dựng của bạn hiện không: lưu trữ các giá trị trong nó khỏi danh sách khởi tạo:

Example::Example(std::vector<Example*> myVec) 
    : m_value(myVec.size() ? myVec.size() + 1 : -1) { 
} 
+1

Điều này giải quyết vấn đề trong trường hợp rất hẹp của ví dụ này. Điều gì về nếu mã để tính toán initializer là phức tạp hơn đáng kể hơn bạn có thể quản lý để phù hợp với một biểu thức? – Omnifarious

+1

@Omnifarious - xem câu trả lời được đưa ra bởi Omnifarious. –

+0

@Omnifarious: Sau đó, bạn viết một helper nhỏ chức năng mà nó –

0

Bạn có hai lựa chọn cơ bản. Một là sử dụng các nhà điều hành có điều kiện, đó là tốt cho điều kiện đơn giản như của bạn:

Example::Example(const std::vector<Example*> &myVec) 
    : m_value(myVec.size() ? myVec.size() + 1 : -1) 
{} 

Đối với những thứ phức tạp hơn, bạn có thể ủy tính toán để một hàm thành viên. Cẩn thận không gọi các hàm thành viên ảo bên trong nó, vì nó sẽ được gọi trong khi xây dựng.Đó là an toàn nhất để làm cho nó static:

class Example 
{ 
    Example(const std::vector<Example*> &myVec) 
    : m_value(initialValue(myVec)) 
    {} 

    static int initialValue(const std::vector<Example*> &myVec) 
    { 
    if (myVec.size()) { 
     return myVec.size() + 1; 
    } else { 
     return -1; 
    } 
    } 
}; 

Cuối cùng cũng làm việc với định nghĩa ngoài lớp, tất nhiên. Tôi đã đặt chúng trong lớp để tiết kiệm không gian & nhập.

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