Các vòng loại sau khi Parens chức năng cuộc gọi áp dụng đối với các ẩn this
tham số của hàm thành viên:
Một chức năng thành viên void Foo::bar()
là loại như thế này: void bar(Foo *this)
. Nhưng điều gì sẽ xảy ra nếu đối tượng Foo là const
?
struct Foo {
void bar();
};
const Foo f{};
f.bar();
Vâng, kể từ Foo::bar()
mất một tham số Foo *this
, mà không được phép được const
, trên f.bar();
thất bại trong việc biên dịch. Vì vậy, chúng ta cần một cách để đủ điều kiện tham số ẩn this
, và cách C++ chọn để làm điều đó là để cho phép các vòng loại đó đi ra ngoài hàm parens.
Cách trình biên dịch phân biệt các hàm này giống hệt nhau theo mọi cách để quá tải hàm bình thường, vì đó chính xác là gì, mặc dù cú pháp lạ.
Hơn nữa, const
không phải là vòng loại duy nhất. Bạn cũng có thể thêm volatile
vòng loại và trong C++ 11, bạn cũng có thể đặt vòng loại tham chiếu lvalue và rvalue.
Lý do chúng tôi cần hai bản sao gần như giống hệt nhau của hàm này là vì không có cách trực tiếp để rút ra một sự khác biệt duy nhất: các loại trả về khác nhau. Nếu chúng ta có một đối tượng const, và đối tượng đó có một getter trả về một tham chiếu đến một cái gì đó nó chứa, tham chiếu đó cần phải đủ điều kiện giống như đối tượng tổng thể.
struct Foo {
int i;
int &get_i() const { return i; }
};
int main() {
const Foo f{};
f.get_i() = 10; // i should be const!
}
trên sẽ thậm chí không biên dịch vì bên Foo::get_i() const
, i
là const, và chúng tôi không thể trả về một tham chiếu không const với nó. Nhưng nếu nó được cho phép, nó sẽ sai vì chúng ta không thể sửa đổi các thành viên của một đối tượng const. Vì vậy, Foo::get_i() const
cần phải trả lại tham chiếu const thành i
.
int const &Foo::get_i() const { return i; }
Nhưng chúng ta nên có thể sửa đổi một thành viên của một đối tượng không const,
int main() {
Foo f{};
f.get_i() = 10; // should be fine
}
vì vậy chúng tôi không thể chỉ có chức năng này. Chúng ta cần một hàm trả về tham chiếu không const khi đối tượng Foo không phải là const. Vì vậy, chúng tôi quá tải chức năng dựa trên const-Ness của đối tượng:
struct Foo {
int i;
int const &get_i() const { return i; }
int &get_i() { return i; }
};
Nếu cơ quan chức năng được nhiều phức tạp có một lựa chọn có thể để tránh trùng lặp:
struct Foo {
int i;
int const &get_i() const { return i; }
int &get_i() { return const_cast<int &>(const_cast<Foo const *>(this)->get_i()); }
};
Đó là, các phi -const quá tải đại biểu thực hiện của nó để quá tải const, bằng cách sử dụng const_cast để sửa chữa các loại. Thêm const luôn an toàn. Việc xóa const bằng cách sử dụng const_cast chỉ an toàn khi chúng ta biết chắc chắn rằng đối tượng ban đầu không phải là const. Chúng ta biết rằng trong trường hợp này, bởi vì chúng ta biết chúng ta đã thêm const vào vị trí đầu tiên cho một đối tượng không phải const.
Gợi ý: người đầu tiên cho phép bạn sửa đổi bất cứ điều gì ' f() 'trả về, có thể là một phần của đối tượng' f() 'đang được gọi. – juanchopanza
Thứ hai không được phép sửa đổi trạng thái của lớp mà phương thức này được xác định. – kerem
http://www.parashift.com/c++-faq/const-overloading.html –