2008-10-02 44 views
15

Ví dụ, giả sử tôi có một lớp:Trong c + +, tại sao trình biên dịch chọn hàm không const khi const cũng làm việc?

class Foo 
{ 
public: 
    std::string& Name() 
    { 
     m_maybe_modified = true; 
     return m_name; 
    } 

    const std::string& Name() const 
    { 
     return m_name; 
    } 
protected: 
    std::string m_name; 
    bool m_maybe_modified; 
}; 

Và ở một nơi khác trong mã, tôi có một cái gì đó như thế này:

Foo *a; 
// Do stuff... 
std::string name = a->Name(); // <-- chooses the non-const version 

Có ai biết lý do tại sao các trình biên dịch sẽ chọn không const phiên bản trong trường hợp này?

Đây là một ví dụ khá khó, nhưng vấn đề thực tế chúng tôi đang cố gắng giải quyết là tự động lưu một đối tượng theo định kỳ nếu nó đã thay đổi và con trỏ phải không phải vì nó có thể bị thay đổi tại một thời điểm nào đó.

+0

Nếu bạn muốn thay đổi một số biến trong hàm const, hãy sử dụng thuộc tính chung. – ypnos

+0

Bạn có nghĩa là "có thể thay đổi" – Lev

+0

... và "biến thành viên", tôi đoán vậy. – Niklas

Trả lời

14

Hai câu trả lời mùa xuân trong tâm trí:

  1. Phiên bản không const là một trận đấu chặt chẽ hơn.

  2. Nếu nó được gọi là quá tải const cho trường hợp không const, sau đó trong những trường hợp nào nó bao giờ gọi là quá tải không const?

Bạn có thể sử dụng quá tải khác bằng cách truyền a đến const Foo *.

Edit: Từ C++ Annotations

Trước đó, trong phần 2.5.11 khái niệm chức năng quá tải là giới thiệu. Ở đó nó lưu ý rằng thành viên chức năng có thể bị quá tải chỉ bởi thuộc tính const của họ. Trong những trường hợp, trình biên dịch sẽ sử dụng viên chức năng hợp chặt chẽ nhất const tuyển của đối tượng:

+0

"Annoations" -> "Chú thích" –

+0

Doh. Cảm ơn, cố định. –

16

Bởi vì một không phải là một con trỏ const. Do đó, một hàm không const là một kết hợp gần hơn. Đây là cách bạn có thể gọi hàm const:

const Foo* b = a; 
std::string name = b->Name(); 

Nếu bạn có quá tải const và không const, và muốn gọi hàm const trên đối tượng không phải const, điều này có thể là dấu hiệu của thiết kế xấu.

+0

Thiết kế đầy đủ khó thể hiện trong ví dụ, nhưng có một vài điểm có thể được cải thiện, tôi chắc chắn ... Hiện tại, chúng tôi thực hiện phương pháp con trỏ const, nhưng nó rất xấu và quan trọng hơn là dựa vào lập trình viên phải nhớ làm như vậy. –

+0

Làm thế nào để cho quá tải const có tên khác? Hoặc có cả một quá tải const và một chức năng khác nhau được đặt tên, một trong những kêu gọi khác trong dòng? – Lev

+0

Chỉ cần một nit để chọn ... con trỏ không phải là const ... đó là một "con trỏ đến const" trong ví dụ của bạn. –

5

Trình biên dịch không tính đến cách bạn đang sử dụng giá trị trả về trong xác định của nó; đó không phải là một phần của quy tắc. Nó không biết nếu bạn đang làm

std::string name = b->Name(); 

hoặc

b->Name() = "me"; 

Nó phải chọn phiên bản mà làm việc trong cả hai trường hợp.

+0

Câu trả lời đúng +1 –

+0

Câu hỏi không phải là về độ chói hay không của giá trị trả về, đó là về độ chói của đối tượng. -1 không phải là tôi mặc dù. –

+0

Tôi hiểu các vấn đề tiềm năng của trình biên dịch, nhưng tôi nghĩ rằng nó sẽ có thể thực hiện một số kiểm tra đơn giản như trong ví dụ, nơi nó sẽ ngay lập tức sử dụng trả lại cho một bản sao và sau đó loại bỏ nó. –

0

Bạn có thể thêm hàm "cName" tương đương với "Tên() const". Bằng cách này, bạn có thể gọi phiên bản const của hàm mà không cần truyền tới đối tượng const trước tiên.

Điều này chủ yếu hữu ích với tự động từ khóa mới trong C++ 0x, đó là lý do tại sao họ đang cập nhật thư viện để bao gồm cbegin(), cend(), crbegin(), crend ​​() để trả về const_iterator ngay cả khi đối tượng không phải là const.

Những gì bạn đang làm có thể được thực hiện tốt hơn bằng cách đặt hàm setName() cho phép bạn thay đổi tên thay vì trả về tham chiếu đến vùng chứa bên dưới và sau đó "có thể" được sửa đổi.

+0

Tôi nhận ra rằng nó có thể tốt hơn với một hàm setName(), nhưng một lần nữa, ví dụ đã phần nào được giả tạo. Trong actuallity, chúng ta có các đối tượng con trỏ có chứa các đối tượng khác, và muốn con trỏ const được trả về khi có thể, khi xâu chuỗi thành "int c = a-> B() -> GetC();", v.v. –

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