2011-08-01 29 views
17

Được rồi, tiêu đề là một lời nói và tôi nghĩ đó có thể là lý do tại sao việc tìm câu trả lời qua google hoặc trang web này là khó khăn. Nó có thể chỉ là tôi không biết làm thế nào để thể hiện vấn đề một cách chính xác nhưng ở đây đi:Phù hợp với chức năng quá tải đối với đối số đa hình

Tôi có một loạt các phương thức trong một lớp học SimpleOpenGLRenderer mà tất cả lấy một đối số duy nhất mở rộng lớp Model. Vì vậy, ý tưởng là tùy thuộc vào loại mô hình, trình kết xuất sẽ gọi phương thức chính xác biết cách hiển thị nó. Dưới đây là một ví dụ thực thi đơn giản dựa trên các vấn đề:

#include <stdio.h> 

class Model {}; 

class Cube : public Model {}; 

class Sphere : public Model {}; 

class Renderer 
{ 
    public: 
    virtual void renderModel(const Model& model) = 0; 
}; 

class SimpleOpenGLRenderer 
{ 
    public: 
    void renderModel(const Cube& model) 
    { 
     printf("Render the cube.\n"); 
    } 

    void renderModel(const Model& model) 
    { 
     printf("Throw an exception, my renderer does not support the model type you have provided.\n"); 
    } 

    void renderModel(const Sphere& model) 
    { 
     printf("Render the sphere.\n"); 
    } 
}; 

int 
main(int argc, char** argv) 
{ 
    Cube cube; 
    Model& model = cube; 
    SimpleOpenGLRenderer renderer; 

    renderer.renderModel(cube); 
    renderer.renderModel(model); 
} 

Kết quả của ví dụ này là:

Render the cube. 
Throw an exception, my renderer does not support the model type you have provided. 

Nó có vẻ hiển nhiên đối với một C++ phát triển dày dạn hơn mà điều này không hoạt động theo kế hoạch nhưng nó không có ý nghĩa với tôi. Khi chạy, tôi sẽ không biết loại chính xác của Model được truyền cho trình kết xuất (do đó quá tải đã cố gắng để giải quyết nó). Đến từ một nền Java, tôi đã sử dụng kỹ thuật này trước và trong Java, phương thức được gọi là sẽ phù hợp nhất với loại đối số thời gian chạy là của đối số. Trong C++ nó có vẻ khớp với kiểu thời gian biên dịch của tham chiếu, ngay cả khi tham chiếu đó có thể kết thúc tới một lớp con - theo ý tôi - phù hợp hơn với một hàm khác.

Cho đến bây giờ tôi đã thực hiện loại đối sánh thời gian chạy này cho phù hợp. Liệu nó đơn giản không tồn tại trong C + + hay tôi đang đi về điều này một cách sai lầm? Tôi có nên làm điều gì đó khác trong C++ để đạt được nó?

Xin cảm ơn,

Gary.

Trả lời

17

Quá tải trong C++ được giải quyết tại thời gian biên dịch, dựa trên loại tĩnh của đối số.

Có một kỹ thuật được gọi là "double-văn" mà có thể được sử dụng:

class Model { 
    virtual void dispatchRender(Renderer &r) const = 0; 
}; 

class Cube : public Model { 
    virtual void dispatchRender(Renderer &r) const { 
     r.renderModel(*this); // type of "this" is const Cube* 
}; 

int main() { 
    Cube cube; 
    Model &model = cube; 
    SimpleOpenGLRenderer renderer; 
    cube.dispatchRender(renderer); 
} 

Lưu ý rằng lớp Renderer cơ sở cần phải chứa tất cả các quá tải mà SimpleOpenGLRenderer hiện đang làm. Nếu bạn muốn nó được cụ thể để SimpleOpenGLRenderer những gì quá tải tồn tại sau đó bạn có thể đặt một chức năng gửi đơn giản cụ thể trong Model, hoặc bạn có thể bỏ qua kỹ thuật này và thay vào đó sử dụng dynamic_cast nhiều lần trong SimpleOpenGLRenderer::renderModel để kiểm tra loại.

+2

Cảm ơn. Tôi đã không sử dụng mô hình đó trước đây. Tôi đoán nó có thể không phổ biến trong Java. Tôi đã thực hiện một số thử nghiệm và tôi nghĩ rằng tôi có thể sẽ quay trở lại giải pháp 'dynamic_cast'. Tôi đã hy vọng cho một cái gì đó thanh lịch hơn nhưng mô hình công văn đôi/khách truy cập dường như giới thiệu tất cả các loại phụ thuộc và khớp nối chặt chẽ mà tôi không quá quan tâm. –

1

Để "quá tải thời gian chạy" dựa trên loại động, bạn có thể sử dụng visitor pattern.

+0

Ah, nhờ liên kết, tôi quên điều đó. Vì vậy, bây giờ, chỉ cần lấy trộm liên kết của bạn. Anh ấy. :-) –

2

Trong mã của bạn, quá tải chức năng được giải quyết dựa trên loại tĩnh của đối số.

Điều bạn cần có thể là cơ chế double-dispatch rất gần với kiểu Khách truy cập. Đọc những:

1

Mã của bạn là một ứng cử viên tốt của kiểu thời gian chạy phù hợp, nếu bạn sử dụng nó. Tại đây bạn nhận được Cube vào Model& và chuyển cùng một cách đơn giản tới renderModel().Cho đến bây giờ bạn không có cơ hội để trình biên dịch sử dụng kiểu thời gian chạy. Nhưng thay vì dựa vào loại tĩnh của đối tượng.

Trong 2 cách bạn có thể đã sử dụng kiểm tra loại thời gian chạy. Một là sử dụng dynamic_cast<> và một cái khác đang cung cấp phương thức giao diện trong Model. tức là

class Model { 
    virtual void print() { printf("throw..."); } // provide an interface method 
}; 

class Cube : public Model { 
    virtual void print() { print("Render cube\n"; } // implement it 
}; 

class Sphere : public Model { 
    virtual void print() { print("Render sphere\n"; } // implement it 
}; 

class SimpleOpenGLRenderer 
{ 
    public: 
    void renderModel(const Model& model) 
    { 
    model.print(); 
    } 
}; 
+0

Tôi nghĩ rằng tôi sẽ sử dụng giải pháp 'dynamic_cast' vì thiếu bất cứ điều gì tốt hơn khi xem xét độ phân giải loại tĩnh. Tôi không muốn 'Mô hình' chịu trách nhiệm cho việc dựng hình bởi vì tôi có 10 Trình hiển thị khác nhau đã thực hiện hiển thị theo nhiều cách khác nhau. –

0

Trong C++ độ phân giải quá tải để gọi, được thực hiện tại thời gian biên dịch.

Để thực hiện hiệu quả phụ thuộc vào loại đối số đa hình, bạn cần tham khảo đối số đó, tức là gọi phương thức ảo trên đối số.

Tôi nghĩ cách sạch nhất để làm điều đó ở đây là những gì được gọi là visitor pattern. SimpleOpenGLRenderer của bạn có thể gọi phương thức model.renderOn(*this). Sau đó Model::renderOn là một tập hợp các quá tải, một cho mỗi loại trình kết xuất có thể, hoặc đó là một phương pháp ảo duy nhất sử dụng dynamic_cast để khám phá loại trình kết xuất. Trong bất kỳ cách nào, sau đó, gọi lại trên trình kết xuất, nhưng bây giờ cuộc gọi đó biết loại trình kết xuất là gì và loại chính nó là gì và cũng có thể gọi phương thức hiển thị rất cụ thể, như, SimpleOpenGLRenderer::renderCube.

Chúc mừng,

0

Các giải pháp khác ở đây sẽ làm chính xác những gì bạn muốn. Nhưng theo ý kiến ​​của tôi với chi phí phức tạp. Nếu vấn đề của bạn là chính xác như mô tả, tôi sẽ đề nghị thay đổi kiến ​​trúc của giải pháp của bạn để thay thế. Không phải trình kết xuất đang cố gắng thực hiện công việc của mô hình? Những gì tôi thấy là một loại câu chuyển đổi tạo ra quá tải.

Làm thế nào về việc các mô hình render themself, có lẽ bằng cách sử dụng một số lớp học cung cấp phương pháp vẽ nguyên thủy hơn:

class Cube : public Model { 
    render(RenderTool& tool) { 
    tool.renderCube(); //or even more low level 
    } 
}; 

class SimpleOpenGLRenderer { 
    public: 
    RenderModel(Model& model) { 
    model.render(renderTool); 
    } 
    private: 
    SomeOpenGLRenderingTool renderTool; 
}; 
+0

Tôi không thấy điều này đơn giản hơn các phương pháp khác được trình bày. Nếu tôi đang sử dụng 'công cụ' để thực hiện kết xuất thì trình kết xuất 'là gì? Nó cảm thấy như một người đàn ông trung niên không mong muốn. Tôi không muốn 'Mô hình' chịu trách nhiệm dựng hình. Việc hiển thị có thể được thực hiện theo nhiều cách khác nhau và thậm chí sử dụng các API đồ họa khác nhau. Trách nhiệm của 'Model' chỉ đơn giản là mô tả hình học. –

+0

Tôi cố gắng tuân theo nguyên tắc chuyên gia thông tin. Trong trường hợp này, Model là người duy nhất biết hình dạng đó. Chuyển sang kiểu để tạo ra một đối tượng bên ngoài làm bản vẽ là IMO là một sự vi phạm không cần thiết của việc đóng gói. Trình kết xuất cho là một câu hỏi hợp lệ. IMO có lẽ mô hình nên sử dụng trình kết xuất chứ không phải ngược lại. – daramarak

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