2010-08-31 11 views
8

Mẫu truy cập có phải là cách nhanh nhất để thực hiện nhận dạng kiểu tham số phương thức (một cách đơn giản có hiệu quả trên một tham số, không phải là lớp của một thành viên) trong C++ không? Tôi có thể biết chính xác (các) phương pháp mà tôi muốn gọi trên các thành phần của loại phụ chưa biết, vì vậy luôn thực hiện một cuộc gọi phương thức ảo bổ sung như V::visit(A *) trong A::accept(V &v) { v.visit(this); } là không mong muốn.Mẫu khách truy cập có phải là cách nhanh nhất để phân biệt các loại thông số trong C++ không?

// Is the Visitor pattern recommended here? (E inherits D inherits B.) 
class Foo { 
public: 
    virtual void visit(B *) { result = 3; } 
    virtual void visit(D *) { result = 4; } 
    virtual void visit(E *) { result = 5; } 
private: 
    int result; 
}; // class Foo 

// Need to add generic interface to B and its children ... 
class B { 
public: 
    virtual void accept(class Foo &f) { f.visit(this); } 
}; // class B 

Tôi muốn một cái gì đó chức năng tương đương các thang sau nhưng với O (1) chi phí, mà là AFAIK không thể với dynamic_cast <> hoặc typeid(), vì std::type_info không thể là một constexpr/chuyển đổi.

// O(n) search cost might get nasty with bigger hierarchies. 
int foo(B *b) { 
    if (typeid(b) == typeid(B *)) { return 1; } 
    if (typeid(b) == typeid(D *)) { return 2; } 
    if (typeid(b) == typeid(E *)) { return 3; } 
    return -1; 
} 

Tùy chọn của tôi ở đây là gì? Cảm ơn vì lời khuyên!

Chỉnh sửa: Đã thay đổi mã mẫu để cung cấp kết quả thông qua trường, vì vậy không cần nhiều chữ ký cho các loại phương thức khác nhau. Cảm ơn, Maurice!

cuối cùng quyết định: Ngoài việc không thích các chi phí văn đôi bắt buộc của mẫu của khách, tôi cũng muốn tránh tích tụ quá giao diện của quá tải foo(), nhưng tôi không nghĩ rằng có một mô hình sạch sẽ biết đến làm cái này. Tôi đã kết thúc chỉ làm quá tải tĩnh thẳng và gọi nó là một ngày. Dù sao, tôi muốn đóng gói quá tải bên trong một chức năng có lẽ là một mục tiêu đáng ngờ nhất. Cảm ơn, Maurice đã trả lời.

+0

cho người đọc sau C++ 11: xem qua thư viện Yorel Multimethod (hiện tại đang được tăng cường) –

Trả lời

3

Thực tế, các giao diện không cần phải trùng lặp. Các lớp con của khách truy cập có thể xử lý các chi tiết của hoạt động. Trong trường hợp của bạn:

class Visitor { 
    virtual void visit(B*) = 0; 
    virtual void visit(D*) = 0; 
    virtual void visit(E*) = 0; 
} 

class Foo: public Visitor { 
private: 
    int result; 
public: 
    void visit(B*) { result = 3; } 
    void visit(D*) { result = 4; } 
    void visit(E*) { result = 5; } 
    int apply(A* a) { 
     a->accept(this); 
     return result; 
    } 
} 

Vì vậy, chỉ cần một phương thức accept() trong mỗi lớp.

Tất cả các lựa chọn thay thế cho mẫu khách truy cập tôi có thể nghĩ đến liên quan đến một số loại tìm kiếm thời gian chạy, vì vậy có, IMHO, mẫu khách truy cập là cách nhanh nhất.

+0

Ah, điểm tốt. Giới thiệu câu hỏi và mã mẫu được cập nhật để phản ánh điều này. – Jeff