2011-07-06 31 views
6

Tôi chỉ nhận ra những câu hỏi khó có thể ... Hy vọng rằng tôi có thể đưa ra các ví dụ vừa đủ vừa đủ để chứng minh vấn đề của tôi và đủ ngắn để không làm mọi thứ rối loạn ... Ít nhất có khả năng chỉnh sửa.C++ Templating vs Inheritance

Vì vậy, đây là loại tình huống của tôi vào lúc này. Tất nhiên tôi thay đổi nó một chút về mặt logic/cấu trúc (và về mặt đặt tên anyway) cố gắng tập trung vào bản chất của câu hỏi của tôi:

// MyClass deals with lists (actually several data structures) of the 
// type MyType which should support different types and has to be 
// efficiently dealt with. Templating seems just right here 
class MyClass 
{ 
    ... 

    void doSomething<class MyType>(vector<MyType> someList); 

    ... 

    // At some point I have to extract elements of the type MyType. 
    // The extractor obviously depends on MyType but it is not possible to 
    // Create a general version that could use templates itself 
    // (unless I use a specialization for each possible MyType) 

    // I am stuck between these two alternatives: 

    // Possibility1: 
    // Let the client pass the right extractor and template it. 
    template<class Extractor, class MyType> 
    void extract(const Extractor& extractor, const string& source, 
       vector<MyType>* dest) 
    { 
    extractor.extract(source, dest); 
    } 

    // Possibility2: 
    // Use a member _extractor of some base type that has to be set 
    // to a specialization. The ExtractorBase has a virtual method 
    // template<T> void extract(const string& source, vector<T>* myType) = 0 
    // with no definition that is only defined in subclasses wrt certain 
    // postings. 
    ExtractorBase _extractor; 

    template<class MyType> 
    void extract(const string& source, vector<MyType>* dest) 
    { 
    _extractor.extract(source, dest); 
    } 
} 

Tại thời điểm tôi muốn possibility1, bởi vì tôi don' t có để gây rối với thừa kế trong Extractor cho tất cả các biến thể của MyType và liên kết Extractor tôi muốn thử trong tương lai.

Mặt khác, các trình giải nén có thể yêu cầu mã phức tạp và một số thành viên (giống như bản đồ lớn ánh xạ các đầu vào nhất định trên các giá trị nhất định). Vì vậy, sẽ không có hiệu suất đạt được bằng cách sử dụng mẫu. Đặc biệt chỉ sử dụng các tệp tiêu đề mà các Trình giải nén và thậm chí có thể là các functors được cho là có được nội tuyến, là loại ra khỏi câu hỏi. Trong quá khứ, đây là một con trỏ mạnh mẽ với tôi rằng việc tạo khuôn mẫu sẽ chỉ làm tăng độ phức tạp của mã (phải đối phó với việc khởi tạo, làm cho cuộc sống khó khăn hơn đối với mã máy khách, v.v) và tôi nên cố gắng tránh nó hoàn toàn.

Hoặc có khả năng thứ ba mà tôi không nghĩ đến?

+0

Bạn có ý nghĩa gì khi 'trích xuất'? Có phải chỉ có vector sẽ được sử dụng? – vines

+0

nó không rõ ràng như thế nào MyClass là tham gia vào quá trình khai thác (và tại sao giải nén() là một _method_ của MyClass?) – user396672

Trả lời

2

Tốt hơn là hãy chọn tùy chọn đầu tiên đầu tiên. Nó sạch hơn và dễ bảo trì hơn.

Bởi vì từ ý kiến ​​của bạn, tôi đang làm hiện ra rằng bạn đang làm cho một giả định sai cho lựa chọn thứ 2:

// The ExtractorBase has a virtual method 
// template<T> void extract(const string& source, vector<T>* myType) = 0; 

NO. Đó là không thể; chức năng template không bao giờ có thể là virtual. Vì vậy, để thực hiện các tùy chọn thứ 2 bạn phải lựa chọn một số cách bẩn và khó để duy trì, đó không phải là một ý tưởng tốt.

+0

Tôi nghĩ Björn có nghĩa là biến thành viên _extractor là một con trỏ, và thực sự trỏ vào một triển khai thích hợp trước khi gọi hàm templated. Đó là khả thi, nhưng tôi không có fan của công văn ảo khi mẫu có thể được sử dụng: nói chung, giải quyết nhiều hơn tại thời gian biên dịch càng tốt. Dù sao, điều này có vẻ là một trường hợp cổ điển của "suck nó và xem" ... bắt đầu với các mẫu, nếu họ gây ra một số rắc rối di chuyển đến công văn ảo ... API có thể được thực tế giống nhau một trong hai cách để công việc liên quan nên được không đáng kể. –

1

Tôi thấy khả năng đầu tiên linh hoạt hơn.

Trong khả năng thứ hai, tôi không thấy sự quan tâm của bộ giải nén đóng gói không cần thiết làm thành viên nhóm. Bạn cũng có nhiều sự kết nối giữa MyClass và Extractor, đây không phải là một điều tốt. templating giảm khớp nối (theo một cách nào đó), vì vậy nếu bạn có sự lựa chọn đó là một tốt hơn.

1

Bạn có tùy chọn thứ ba, cung cấp hàm tạo cho MyType biết cách tự xây dựng từ std::string. Hoặc tốt hơn là một cặp lặp, vì vậy nếu bạn cần xây dựng một chuỗi gồm MyType s từ chuỗi, bạn có thể sử dụng dải đó.

+0

Trước hết tôi phải trích xuất nhiều MyTypes từ một chuỗi, do đó chỉ rời khỏi vòng lặp. Trong khi đó là ý tưởng agreat tôi nên thêm rằng vắt phụ thuộc vào rất nhiều thông tin bổ sung. Ví dụ tốt nhất có thể là một "từ vựng" ánh xạ các chuỗi đầu vào tới các ID. Vẫn cảm ơn rất nhiều sự giúp đỡ của bạn. –

+0

@ b.buchhold, có lẽ tất cả thông tin đó là chi tiết triển khai nội bộ của 'MyType'? – Nim

0

Điều này nghe có vẻ giống như trường hợp của Strategy Pattern - lớp học của bạn có một hoạt động mà việc triển khai có thể khác nhau.

Đây là sự cân bằng mà tôi thấy trong các cách tiếp cận khác nhau.

Giải pháp mẫu sẽ tránh phải khai báo lớp giao diện trừu tượng và sử dụng vtbl để tìm hiểu triển khai nào sẽ sử dụng. Nhưng nó sẽ buộc bạn phải khóa vào ứng dụng tại thời gian biên dịch.

Giải pháp kế thừa sẽ buộc bạn khai báo lớp giao diện trừu tượng và thực hiện lần truy cập hiệu suất trong việc thực hiện vtbl. Nhưng nó sẽ cho phép bạn chọn triển khai trích xuất khi chạy.

Không biết hiệu suất quan trọng đối với ứng dụng của bạn như thế nào, bạn có thể chọn giải pháp kế thừa vì tôi thích độ rõ ràng của giao diện trong lớp trừu tượng và mã hóa.