2014-08-29 35 views
5

Tôi đã tự hỏi làm thế nào bảo vệ một thành viên con trỏ không const từ một đối tượng thông qua một phương pháp const. Ví dụ:Phương pháp C++ const trên thành phần con trỏ không const

class B{ 
    public: 
     B(){ 
      this->val=0; 
     } 

     void setVal(){ 
      this->val = 2; 
     } 

    private: 
     int val; 
}; 

class A{ 
    public: 
     A():b(new B){} 
     void changeMemberFromConstMethod() const{ 
      this->b->setVal(); 
     } 
    private: 
     B * b; // how to protect data pointed in A::changeMemberFromConstMethod 
} 

Có thể "bảo vệ" dữ liệu A :: b được chỉ ra từ phương pháp của anh không? Sau nhiều nghiên cứu trên web, không có phản hồi hài lòng nào được tìm thấy.

Cảm ơn sự giúp đỡ của bạn.

+6

"Bác sĩ, nó đau khi tôi làm điều này" - "Vì vậy, không làm điều đó". Nó không giống như bất cứ ai xoắn cánh tay của bạn và buộc bạn gọi 'setVal' từ một phương pháp const. Tôi cho rằng tôi không hiểu bản chất của vấn đề. –

+0

Nó chỉ nhằm mục đích ví dụ. Ví dụ Nó giống như một đảm bảo tôi muốn thiết lập tức là không sửa đổi dữ liệu B. – Alex

+0

Nếu bạn không muốn sửa đổi '* b', thì không cần. Tôi vẫn không hiểu bản chất của những khó khăn. –

Trả lời

10

Something như thế này, có lẽ:

template <typename T> 
class deep_const_ptr { 
    T* p_; 
public: 
    deep_const_ptr(T* p) : p_(p); 

    T* operator->() { return p_;} 
    const T* operator->() const { return p_;} 
}; 

class A { 
    deep_const_ptr<B> b = new B; 
}; 

deep_const_ptr cư xử như một con trỏ const T* const trong các phương pháp const A 's, và giống như T* trong các phương pháp không const. Fleshing lớp ra xa hơn là trái như là một bài tập cho người đọc.

+1

+1 Giải pháp hay. –

+0

Thật thú vị! Nhưng làm thế nào các nhà điều hành phải được chọn? – Alex

+2

Bởi quá tải resoultion, tất nhiên. Còn cách nào khác? –

6

Nếu bạn thay đổi thành viên của A từ

B* b; 

để

B b; 

sau đó bạn sẽ nhận được các hành vi mong đợi.

class A{ 
    public: 
     A() : b() {} 

     void changeMemberFromConstMethod() const{ 
      this->b.setVal(); // This will produce a compiler error. 
     } 
    private: 
     B b; 
} 
+1

Tôi biết điều đó. Cảm ơn – Alex

4

Vấn đề bạn có là một phương pháp const làm cho tất cả các biến thành viên const. Trong trường hợp này tuy nhiên, nó làm cho con trỏ const. Cụ thể, nó giống như tất cả những gì bạn có là B * const b, có nghĩa là một con trỏ liên tục đến một (vẫn) có thể thay đổi B. Nếu bạn không khai báo biến thành viên của bạn là const B * b, (nghĩa là, một con trỏ có thể thay đổi thành hằng số B), thì không có cách nào để bảo vệ khỏi hành vi này.

Nếu tất cả bạn cần là một const B, sau đó bằng mọi cách, xác định A như thế này:

class A { 
public: 
    A() : b(new B) {} 

    // This WILL give an error now. 
    void changeMemberFromConstMethod() const { b->setVal(); } 
private: 
    const B* b; 
} 

Tuy nhiên, nếu các phương pháp khác của A đột biến B, sau đó tất cả các bạn có thể làm là đảm bảo rằng B làm không bị đột biến trong các phương thức const của bạn là A.

+0

Tôi đồng ý với bạn. Nhưng nếu tôi đặt: void changeMemberFromConstMethod() {b-> setVal();} Điều này sẽ không thành công. Tôi muốn rằng phương pháp const nói rằng: const B * b const; bạn thấy không – Alex

1

Hãy thử sử dụng cách tiếp cận chung sau đây, để bảo vệ const-ness của các đối tượng được tham chiếu qua con trỏ, trong tình huống này.

  1. Rename B * b

    B *my_pointer_to_b; 
    

    Và thay đổi khởi tạo trong constructor cho phù hợp.

  2. Thực hiện hai cuống:

    B *my_b() { return b; } 
    const B *my_b() const { return b; } 
    
  3. Thay thế tất cả tài liệu tham khảo hiện có để b với my_b(), trong các mã hiện có. Về sau, trong bất kỳ mã mới nào, luôn sử dụng hàm my_b() để trả về con trỏ đến b.

Phương pháp có thể thay đổi sẽ có con trỏ không đến B; Các phương thức const sẽ nhận được một con trỏ const tới B và bước bổ sung của việc đổi tên đảm bảo rằng tất cả các mã hiện có buộc phải tuân thủ chế độ mới.

+0

Đó là một cách tiếp cận intersting. Nhưng đó là một chút xoắn ^^. Làm thế nào có thể là phương pháp đúng được tìm thấy theo phương pháp const hay không? – Alex

+1

Một phương thức const chỉ có thể gọi các phương thức const khác. Trong một phương thức const, "this" là một con trỏ không đổi, không phải là một con trỏ có thể thay đổi được. Đây thực sự là một mẫu thiết kế khá phổ biến. –

+0

Cảm ơn ánh sáng của bạn – Alex

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