2012-05-05 30 views
7

Người ta nói rằng toán tử mũi tên được áp dụng đệ quy. Nhưng khi tôi cố gắng để thực hiện đoạn mã sau, nó in vô nghia khi nó là vụ phải in 4.ứng dụng đệ quy của toán tử->

class dummy 
{ 
public: 
    int *p; 

    int operator->() 
    { 
     return 4; 
    } 
}; 

class screen 
{ 
public: 
    dummy *p; 

    screen(dummy *pp): p(pp){} 
    dummy* operator->() 
    { 
     return p; 
    } 
}; 

int main() 
{ 
    dummy *d = new dummy; 
    screen s(d); 
    cout<<s->p; 
    delete d; 
} 
+6

Trường hợp nói rằng nó được "áp dụng đệ quy"? –

+0

Không, tôi không đồng ý ví dụ của bạn hoạt động như mong đợi, -> opertor chỉ là một cuộc gọi hàm trong bản chất, tại sao nó nên đi sâu? Nếu nó làm điều đó như thế nào bạn sẽ kiểm soát ở mức độ để ngăn chặn dereferencing và nó sẽ làm cho thừa kế và đa hình thậm chí phức tạp hơn nó đã là – EdChum

+2

C++ Primer, Ấn bản thứ tư Bởi Stanley B. Lippman, phần 14.6 đoạn cuối cùng. – user1232138

Trả lời

10

gì Stanley nghĩa của “đệ quy” chỉ là rằng các nhà điều hành được áp dụng cho mọi đối tượng quay trở lại cho đến khi sự kiểu trả về là một con trỏ.

Điều gì xảy ra ở đây trong lần thử đầu tiên: screen::operator -> trả về một con trỏ. Vì vậy, đây là cuộc gọi cuối cùng đến một operator -> mà trình biên dịch thử. Sau đó, nó sẽ xử lý con xúc xắc bên phải của toán tử (p) bằng cách tra cứu một thành viên theo kiểu con trỏ trả về (dummy) với tên đó.

Về cơ bản, bất cứ khi nào trình biên dịch thấy cú pháp aᵢ->b trong mã, nó chủ yếu áp dụng các thuật toán sau đây:

  1. aᵢ kiểu con trỏ? Nếu có, hãy giải quyết thành viên b của số *aᵢ và gọi (*aᵢ).b.
  2. Khác, cố gắng giải quyết aᵢ::operator ->
    1. Khi thành công, hãy đặt aᵢ₊₁ = aᵢ::operator ->(). Goto 1.
    2. Khi lỗi, phát ra lỗi biên dịch.

tôi cứng ép để đến với một đoạn ngắn, ví dụ có ý nghĩa, nơi một chuỗi của operator -> invocations thậm chí có ý nghĩa. Có lẽ chỉ sử dụng thực sự là khi bạn viết một lớp con trỏ thông minh.

Tuy nhiên, ví dụ về đồ chơi sau đây ít nhất là biên dịch và mang lại một con số. Nhưng tôi sẽ không khuyên thực sự viết mã như vậy. Nó phá vỡ đóng gói và làm cho mèo con khóc.

#include <iostream> 

struct size { 
    int width; 
    int height; 
    size() : width(640), height(480) { } 
}; 

struct metrics { 
    size s; 
    size const* operator ->() const { 
     return &s; 
    } 
}; 

struct screen { 
    metrics m; 
    metrics operator ->() const { 
     return m; 
    } 
}; 

int main() { 
    screen s; 
    std::cout << s->width << "\n"; 
} 
+0

có lẽ khái niệm của tôi sẽ rõ ràng hơn nếu bạn có thể cho tôi biết làm thế nào tôi có thể nhận được 4 để được in ra trong ví dụ này .. – user1232138

+0

@ user1232138 Bạn không thể. Cuộc gọi cuối cùng trong chuỗi toán tử '->' ** phải ** trả về một con trỏ. –

+0

@ user1232138 Tuy nhiên, hãy xem bản cập nhật của tôi để có ví dụ hoạt động. Lưu ý rằng những gì tôi đã nói trước đây vẫn giữ. Bạn phải trả về một con trỏ - vì vậy nếu bạn muốn lấy một giá trị số nguyên, nó cần phải được lưu trữ trong biểu thức bên phải của toán tử (trong trường hợp này là 'size :: width'). –

0

Thỏa thuận này là một lần screen::operator->() trả về một con trỏ (dummy*) đệ quy dừng vì built-in (mặc định) -> trong sử dụng trên con trỏ đó. Nếu bạn muốn đệ quy bạn nên trở dummy hoặc dummy& từ screen::operator->()

1

C++ Primer (5th edition) formulates nó như sau trên trang 570:

Mũi tên nhà điều hành không bao giờ mất đi ý nghĩa cơ bản của nó tiếp cận thành viên. Khi chúng ta quá tải mũi tên, chúng ta thay đổi đối tượng mà từ đó mũi tên nạp thành viên được chỉ định. Chúng tôi không thể thay đổi thực tế là mũi tên tìm nạp thành viên.

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