2012-05-20 24 views
28

Tôi hiểu quá tải toán tử bình thường. Trình biên dịch có thể dịch chúng sang phương thức gọi trực tiếp. Tôi không rõ lắm về toán tử ->. Tôi đã viết iterator tùy chỉnh đầu tiên của tôi và tôi cảm thấy cần sự điều hành ->. Tôi đã xem xét mã nguồn STL và thực hiện của riêng tôi như nó:Cách thức hoạt động của arrow-> overload trong nội bộ C++?

MyClass* MyClassIterator::operator->() const 
{ 
    //m_iterator is a map<int, MyClass>::iterator in my code. 
    return &(m_iterator->second); 
} 

Sau đó, tôi có thể sử dụng một thể hiện của MyClassIterator như:

myClassIterator->APublicMethodInMyClass(). 

Hình như trình biên dịch thực hiện hai bước ở đây. 1. Gọi phương thức ->() để nhận biến MyClass * tạm thời. 2. Gọi APublicMethodInMyClass trên biến tạm thời sử dụng toán tử ->.

Sự hiểu biết của tôi có đúng không?

Trả lời

23
myClassIterator->APublicMethodInMyClass() 

là gì, nhưng những điều sau:

myClassIterator.operator->()->APublicMethodInMyClass() 

Cuộc gọi đầu tiên đến quá tải operator-> giúp bạn một con trỏ của một số loại trong đó có một chức năng thành viên truy cập (từ gọi trang web của bạn) gọi là APublicMethodInMyClass(). Các quy tắc tra cứu chức năng thông thường được theo sau để giải quyết APublicMethodInMyClass(), tất nhiên, tùy thuộc vào việc nó có phải là ảo hay không.

Không nhất thiết phải là biến tạm thời; trình biên dịch có thể hoặc không thể sao chép con trỏ được trả về bởi &(m_iterator->second). Trong tất cả các xác suất, điều này sẽ được tối ưu hóa đi. Không có đối tượng tạm thời thuộc loại MyClass sẽ được tạo ra.

Thông báo trước cũng áp dụng cho m_iterator - đảm bảo rằng cuộc gọi của bạn không truy cập vào trình lặp vòng không hợp lệ (ví dụ: nếu bạn đang sử dụng vector chẳng hạn).

+2

Thực ra đó là 'myClassIterator.operator ->() -> APublicMethodInMyClass()' –

+0

Cảm ơn bạn đã giải thích. Nên myClassIterator.operator ->() APublicMethodInMyClass() là myClassIterator.operator ->() -> APublicMethodInMyClass()? Kiểu trả về của ->() là MyClass * – Ryan

+0

đã nhận. Cảm ơn Seth. – Ryan

66

operator-> có ngữ nghĩa đặc biệt bằng ngôn ngữ trong đó, khi quá tải, nó tự áp dụng lại vào kết quả. Trong khi phần còn lại của các toán tử chỉ được áp dụng một lần, operator-> sẽ được trình biên dịch áp dụng nhiều lần khi cần đến một con trỏ thô và một lần nữa để truy cập bộ nhớ được trỏ bởi con trỏ đó.

struct A { void foo(); }; 
struct B { A* operator->(); }; 
struct C { B operator->(); }; 
struct D { C operator->(); }; 
int main() { 
    D d; 
    d->foo(); 
} 

Trong ví dụ trước, trong biểu thức d->foo() trình dịch sẽ coi đối tượng d và áp dụng operator-> với nó, trong đó sản lượng một đối tượng kiểu C, sau đó nó sẽ áp dụng lại các nhà điều hành để có được một thể hiện của B, nộp đơn xin lại và nhận được A*, sau đó nó sẽ dereference đối tượng và nhận được để các dữ liệu nhọn.

d->foo(); 
// expands to: 
// (*d.operator->().operator->().operator->()).foo(); 
// D   C   B   A* 
+1

Bạn có thể chỉ cho tôi tham chiếu về điều này không? Có vẻ như không thể tìm thấy bất kỳ. Không ai khác đề cập đến nó. –

+7

@MilindR: 13.5.6/1 [...] * Một biểu thức x-> m được hiểu là '(x.operator ->()) -> m' cho một đối tượng lớp x của kiểu T nếu' T: : toán tử ->() 'tồn tại và nếu toán tử được chọn là hàm kết hợp tốt nhất bởi cơ chế giải quyết quá tải * Nếu' x-> toán tử ->() 'sinh ra một con trỏ, nó sẽ bị hủy tham chiếu, nếu nó tạo ra một đối tượng một kiểu mà quá tải 'toán tử ->()' toán tử đó được gọi. –

+2

Đây phải là câu trả lời đúng. –

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