Những gì bạn đang yêu cầu được gọi là multiple dispatch, còn gọi là multimethods. Nó không phải là một tính năng của ngôn ngữ C++.
Có giải pháp cho các trường hợp đặc biệt, nhưng bạn không thể tránh tự mình thực hiện một số thao tác.
Một mẫu phổ biến cho nhiều công văn được gọi là "redispatch", còn gọi là "gửi đi trì hoãn đệ quy". Về cơ bản, một phương thức ảo giải quyết một kiểu tham số sau đó gọi một phương thức ảo khác, cho đến khi tất cả các tham số được giải quyết. Chức năng của bên ngoài (nếu có) chỉ gọi phương thức ảo đầu tiên.
Giả sử có n lớp dẫn xuất, sẽ có một phương pháp để giải quyết tham số đầu tiên, n để giải quyết tham số thứ hai, n * n để giải quyết vấn đề thứ ba và cứ thế - tệ nhất. Đó là một số tiền hợp lý của công việc thủ công, và sử dụng các khối điều kiện dựa trên typeid có thể dễ dàng hơn cho sự phát triển ban đầu, nhưng nó mạnh mẽ hơn để bảo trì sử dụng redispatch.
class Base;
class Derived1;
class Derived2;
class Base
{
public:
virtual void Handle (Base* p2);
virtual void Handle (Derived1* p1);
virtual void Handle (Derived2* p1);
};
class Derived1 : public Base
{
public:
void Handle (Base* p2);
void Handle (Derived1* p1);
void Handle (Derived2* p1);
};
void Derived1::Handle (Base* p2)
{
p2->Handle (this);
}
void Derived1::Handle (Derived1* p1)
{
// p1 is Derived1*, this (p2) is Derived1*
}
void Derived1::Handle (Derived2* p1)
{
// p1 is Derived2*, this (p2) is Derived1*
}
// etc
Thực hiện điều này bằng cách sử dụng mẫu cho các lớp học có nguồn gốc sẽ rất khó, và các mẫu Lập trình meta để xử lý nó có lẽ sẽ không thể đọc được, unmaintainable và rất mong manh. Triển khai công văn bằng cách sử dụng các phương thức không phải mẫu, sau đó sử dụng một mẫu mixin (một lớp mẫu lấy lớp cơ sở của nó làm tham số mẫu) để mở rộng với các tính năng bổ sung có thể không quá tệ.
visitor design pattern liên quan chặt chẽ đến (cơ bản được triển khai bằng cách sử dụng) redispatch IIRC.
Cách tiếp cận khác là sử dụng ngôn ngữ được thiết kế để xử lý sự cố và có một vài tùy chọn hoạt động tốt với C++. Một là sử dụng treecc - một ngôn ngữ dành riêng cho miền để xử lý các nút AST và các phép toán nhiều công văn, như lex và yacc, tạo ra "mã nguồn" làm đầu ra.
Tất cả việc cần làm để xử lý các quyết định gửi là tạo các câu lệnh chuyển đổi dựa trên ID nút AST - có thể dễ dàng là ID lớp giá trị được nhập động, IYSWIM. Tuy nhiên, đây là những câu lệnh chuyển đổi mà bạn không phải viết hoặc duy trì, đó là một sự khác biệt chính. Vấn đề lớn nhất mà tôi có là các nút AST bị xử lý hủy hoại của chúng giả mạo, có nghĩa là các destructors cho dữ liệu thành viên không được gọi trừ khi bạn thực hiện một nỗ lực đặc biệt - tức là nó hoạt động tốt nhất với các loại POD cho các trường.
Một tùy chọn khác là sử dụng bộ xử lý tiền xử lý ngôn ngữ hỗ trợ đa phương thức. Đã có một vài trong số này, một phần vì Stroustrup đã có những ý tưởng phát triển khá tốt để hỗ trợ multimethods tại một thời điểm. CMM là một. Doublecpp là loại khác. Tuy nhiên, khác là Frost Project. Tôi tin rằng CMM là gần nhất với những gì Stroustrup mô tả, nhưng tôi đã không kiểm tra.
Cuối cùng, mặc dù, nhiều công văn chỉ là một cách để đưa ra quyết định thời gian chạy và có nhiều cách để xử lý cùng một quyết định. DSL chuyên gia mang lại một số tiền hợp lý của rắc rối, vì vậy bạn thường chỉ làm điều đó nếu bạn cần rất nhiều công văn nhiều. Redispatch và mô hình khách truy cập là bảo trì WRT mạnh mẽ, nhưng với chi phí phức tạp và lộn xộn. Các câu lệnh điều kiện đơn giản có thể là một lựa chọn tốt hơn cho các trường hợp đơn giản, mặc dù hãy cẩn thận rằng việc phát hiện khả năng của một trường hợp không được giải quyết lúc biên dịch là rất khó nếu không phải là không thể.
Như thường lệ, không có cách nào phù hợp để làm điều đó, ít nhất là trong C++.
Tôi nghĩ bạn nên đề cập rằng bạn không biết loại lớp hoàn chỉnh. Bạn chỉ biết 'Base &'. Một số câu trả lời, bao gồm cả câu trả lời của riêng tôi, đã giả sử bạn biết loại chính xác 'Có nguồn gốc '. –
Lưu ý từ một nhận xét về câu trả lời: Một yêu cầu bổ sung là hàm không thể là mẫu; nó phải có chữ ký Base (Base & Base). –
Kết hợp các hạn chế rõ ràng hơn vào câu hỏi. –