2009-08-21 32 views
9

Tôi nhận được biên dịch lỗi sau đây trong một lớp học của tôi, sử dụng gcc 3.4.5 (mingw):yêu cầu cho thành viên '...' là mơ hồ trong g ++

src/ModelTester/CModelTesterGui.cpp:1308: error: request for member `addListener' is ambiguous 
include/utility/ISource.h:26: error: candidates are: void utility::ISource<T>::addListener(utility::IListener<T>*) [with T = const SConsolePacket&] 
include/utility/ISource.h:26: error:     void utility::ISource<T>::addListener(utility::IListener<T>*) [with T = const SControlPacket&] 

Hy vọng rằng bạn có thể thấy rằng ISource<T> là giao diện mẫu chỉ cho biết đối tượng có thể là người cung cấp thông tin cho đối tượng có một số loại đối sánh IListener<T>. Vì vậy, điều mà tôi đã lúng túng là ý tưởng này cho rằng một số lý do chức năng là mơ hồ khi, theo như tôi có thể nói, họ không. Phương thức addListener() bị quá tải cho các loại đầu vào khác nhau IListener<const SConsolePacket&>IListener<const SControlPacket&>. Việc sử dụng là:

m_controller->addListener(m_model); 

đâu m_model là một con trỏ đến một đối tượng IRigidBody, và IRigidBody thừa hưởng chỉ từ IListener< const SControlPacket& > và chắc chắn không phải từ IListener< const SConsolePacket& >

Là một kiểm tra sanity, tôi sử dụng doxygen để tạo ra các sơ đồ phân cấp lớp và doxygen đồng ý với tôi rằng IRigidBody không lấy được từ IListener< const SConsolePacket& >

Rõ ràng sự hiểu biết của tôi về tính kế thừa trong c + + là không chính xác. Tôi có ấn tượng rằng IListener<const SControlPacket&>IListener<const SConsolePacket&> hai loại khác nhau, và rằng tờ khai chức năng

addListener(IListener<const SConsolePacket&>* listener) 

addListener(IListener<const SControlPacket&>* listener) 

tuyên bố hai chức năng riêng biệt mà làm hai việc riêng biệt tùy thuộc vào (riêng biệt) loại tham số khác là đầu vào. Hơn nữa, tôi theo ấn tượng rằng một con trỏ đến một IRigidBody cũng là một con trỏ đến một IListener<const SControlPacket&> và bằng cách gọi addListener(m_model) trình biên dịch nên hiểu rằng tôi đang gọi thứ hai của hai hàm trên.

Tôi thậm chí đã cố gắng đúc m_model như thế này:

m_controller->addListener(
     static_cast<IListener<const SControlPacket&>*>(m_model)); 

nhưng vẫn nhận được lỗi đó. Tôi không thể cho cuộc sống của tôi thấy những chức năng này mơ hồ như thế nào. Có ai có thể làm sáng tỏ vấn đề này không?

P.S. Tôi biết cách buộc chức năng trở nên không rõ ràng bằng cách thực hiện điều này:

m_controller->ISource<const SControlPacket&>::addListener(m_model); 

Tôi chỉ nghĩ rằng điều đó không thể đọc được và tôi không muốn làm điều đó.

Chỉnh sửa ... chỉ đùa thôi. Đó dường như không giải quyết vấn đề vì nó dẫn đến một lỗi mối liên kết:

CModelTesterGui.cpp:1312: undefined reference to `utility::ISource<aerobat::SControlPacket const&>::addListener(utility::IListener<SControlPacket const&>*)' 
+0

Mối quan hệ giữa SControlPacket và SConsolePacket là gì? – GRB

+0

Bạn có thể vui lòng thêm lý do tại sao dòng cuối cùng 'm_controller-> ISource :: addListener (m_model);' làm xáo trộn cuộc gọi? Nếu các hàm bị quá tải, chúng phải ở cùng một lớp. Các hàm đó được khai báo ở đâu? –

+0

@GRB Không có mối quan hệ nào. Cả hai đều là cấu trúc của nguồn gốc từ không có gì. @litb Tôi đã sai về điều đó. Nó làm cho nó biên dịch nhưng nó quay ra dẫn đến một lỗi liên kết khi liên kết đi để cố gắng tìm ISource <...> :: addListener (...) mà là thuần ảo. Bây giờ tôi rất bối rối. Khi bạn nói tuyên bố tôi giả sử bạn có nghĩa là xác định. Chúng được định nghĩa trong các lớp concerete bắt nguồn từ IController. – cheshirekow

Trả lời

20

Hình như tình hình của bạn là như thế này:

struct A { 
    void f(); 
}; 

struct B { 
    void f(int); 
}; 

struct C : A, B { }; 

int main() { 
    C c; 
    c.B::f(1); // not ambiguous 
    c.f(1); // ambiguous 
} 

Cuộc gọi thứ hai để f là mơ hồ, bởi vì trong nhìn lên tên, nó tìm thấy các hàm trong hai phạm vi lớp cơ sở khác nhau. Trong tình huống này, tra cứu là mơ hồ - chúng không quá tải lẫn nhau. Một sửa chữa sẽ là sử dụng một khai báo sử dụng cho mỗi tên thành viên.Tra cứu sẽ tìm thấy tên trong phạm vi C và không tra cứu thêm:

struct C : A, B { using A::f; using B::f; }; 

Bây giờ, cuộc gọi sẽ tìm thấy hai chức năng, làm độ phân giải quá tải, và thấy rằng một trong những tham int sẽ phù hợp. Chuyển sang mã của bạn, điều đó có nghĩa là bạn phải làm điều gì đó như sau

struct controller : ISource<const SConsolePacket&>, ISource<const SControlPacket&> { 
    using ISource<const SConsolePacket&>::addListener; 
    using ISource<const SControlPacket&>::addListener; 
}; 

Bây giờ, hai tên này nằm trong cùng phạm vi và giờ đây chúng có thể quá tải lẫn nhau. Tra cứu bây giờ sẽ dừng lại ở lớp điều khiển, không đi sâu hơn vào hai nhánh cơ sở.

+0

NICE! Vì vậy, đó là những gì những điều đó cho. Tôi không nghĩ rằng tôi đã bao giờ thực sự hiểu bằng cách sử dụng khai báo (một hệ quả của việc không thực sự tìm hiểu tên tra cứu). Cảm ơn nhiều. Như một lưu ý, tôi thực sự đặt khai báo sử dụng trong giao diện IController. Tôi nghĩ đó là nơi thích hợp cho nó. – cheshirekow

+0

Ít nhất trong g ++, không được phép sử dụng hai lần sử dụng. Bạn có thể chọn A :: f hoặc B :: f trong lớp dẫn xuất C. – Dingle

+0

Cảm ơn! Như mọi khi một câu trả lời thực sự rõ ràng và ngắn gọn: D –

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