2012-01-06 19 views
16

Tôi sử dụng mixin mẫu trong C++ rất nhiều, nhưng tôi tự hỏi tại sao kỹ thuật này không được sử dụng nhiều hơn. Nó có vẻ như cuối cùng trong tái sử dụng. Sự kết hợp giữa sức mạnh và hiệu quả này là một trong những lý do tôi thực sự yêu thích C++ và không thể thấy bản thân mình chuyển sang ngôn ngữ JIT.Tại sao mixin mẫu trong C++ không phải là một trụ cột chính?

Bài viết này: http://www.thinkbottomup.com.au/site/blog/C%20%20_Mixins_-_Reuse_through_inheritance_is_good là một nền tảng tốt nếu bạn không biết chúng là gì và đặt trường hợp rõ ràng về mặt sử dụng lại và hiệu suất.

+0

Các ngôn ngữ JIT có thể mạnh mẽ như C++ cho tất cả trừ các ứng dụng * xử lý nhiều nhất *. – GManNickG

+4

@GMan: Tôi nghĩ rằng tham chiếu JIT không liên quan đến câu hỏi.Đó là một câu hỏi hay - đó là một mẫu thiết kế thú vị mà tôi chưa từng thấy ở bất kỳ cơ sở mã nào mà tôi đã từng làm việc. – Skizz

+0

@Skizz: Hoàn toàn không liên quan, tôi đồng ý; nhưng nó ở đó. – GManNickG

Trả lời

20

Vấn đề với mixin là ... xây dựng.

class Base1 { public: Base1(Dummy volatile&, int); }; 

class Base2 { public: Base2(Special const&, Special const&); }; 

Và bây giờ, siêu mixin tôi:

template <typename T> 
struct Mixin: T {}; 

Bạn có nhận thấy vấn đề ở đây? Làm thế nào địa ngục tôi phải vượt qua các đối số cho các nhà xây dựng của lớp cơ sở? Loại constructor nào cần Mixin đề xuất?

Đó là một vấn đề khó khăn và chưa được giải quyết cho đến khi C++ 11 nâng cao ngôn ngữ để nhận được chuyển tiếp hoàn hảo.

// std::foward is in <utility> 

template <typename T> 
struct Mixin: T { 
    template <typename... Args> 
    explicit Mixin(Args&&... args): T(std::forward<Args>(args...)) {} 
}; 

Lưu ý: kiểm tra đôi được chào đón

Vì vậy tại chúng ta thực sự có thể sử dụng mixins ... và chỉ cần phải thay đổi thói quen người :)

Tất nhiên, cho dù chúng tôi thực sự muốn trở thành một chủ đề hoàn toàn khác.

Một trong những vấn đề với mixin (bài viết bạn tham khảo vui vẻ bỏ qua) là cách ly phụ thuộc bạn hoàn toàn mất ... và thực tế là người dùng LoggingTask sau đó bị ràng buộc để viết các phương thức mẫu. Trong các cơ sở mã rất lớn, sự chú ý nhiều hơn được trao cho các phụ thuộc hơn là hiệu năng, bởi vì các phụ thuộc ghi chu kỳ của con người trong khi hiệu suất chỉ ghi chu kỳ CPU ... và những cái đó thường rẻ hơn.

+1

Điều đó vượt quá vấn đề thực tế một chút - có thể chuyển tiếp một số lượng nhỏ các đối số bằng một chút bông (mẫu Mixin rõ ràng (const X & x): T (x) {} mẫu Mixin rõ ràng (X &, Y &): T (x, y) {} ...), hoặc một số hữu hạn lớn với một chút yêu cầu tiền xử lý xấu xí .... –

+2

@TonyDelroy: oh tin rằng tôi đã thử. Với sự kết hợp của 'const',' volatile' và '&' vs "value, nó sẽ sớm trở thành không thể thu được. Tất nhiên, đối với "một" trường hợp cụ thể, nó có thể hoạt động khá tốt, nói chung mặc dù rất khó. Và tất nhiên, như đã nêu trong đoạn lớn hơn, trong khi bây giờ nó là khả thi về mặt kỹ thuật, nó có thể vẫn không được mong muốn vì những lý do khác. –

+0

Tôi đã nghĩ đến việc sử dụng một đặc điểm của lớp học để giải quyết vấn đề này ở một mức độ nào đó (mặc dù không bao giờ cố gắng để thử nó!). Ý tưởng là mỗi mixin tuyên bố một kiểu lồng nhau được gọi là, ModelTraits bao gồm T :: ModelTraits như một thành viên. Lưu ý rằng đây là định nghĩa đệ quy đệ quy. ModelTraits được sử dụng để khởi tạo lớp và T :: ModelTraits có thể được truyền cho hàm tạo lớp cơ sở. –

5

Mẫu yêu cầu triển khai phải hiển thị trong đơn vị dịch, không chỉ ở thời gian liên kết (C++ 11 địa chỉ nếu bạn chỉ sử dụng con trỏ hoặc tham chiếu đến instantiations). Đây là vấn đề chính đối với mã cấp thấp trong môi trường doanh nghiệp: thay đổi để triển khai sẽ kích hoạt (có thể hoặc không thể tự động) số lượng lớn thư viện và ứng dụng khách biên dịch, thay vì chỉ cần relinking.

Ngoài ra, mỗi bản mẫu sẽ tạo ra một loại riêng biệt, có nghĩa là các chức năng có ý định làm việc trên bất kỳ bản mẫu nào có thể chấp nhận chúng - hoặc bản thân chúng bị buộc phải có templated hoặc chúng cần một hình thức bàn giao đa hình thời gian chạy (thường đủ dễ làm: chỉ cần một lớp cơ sở trừu tượng thể hiện tập hợp các hoạt động được hỗ trợ, và một số hàm "get me a accessor" trả về một đối tượng có nguồn gốc với một con trỏ tới instantiation template và entires liên quan trong bảng công văn ảo).

Dù sao, các vấn đề này thường có thể quản lý được, nhưng các kỹ thuật quản lý khớp nối, phụ thuộc và giao diện liên quan ít được công bố, hiểu và sẵn sàng hơn so với kỹ thuật mixin đơn giản. Điều này cũng đúng với các mẫu và lớp chính sách BTW.

+0

Tôi thấy việc sử dụng giao diện trừu tượng là cách chính để tránh khớp nối và do đó lo lắng về biên dịch. Tôi nghĩ rằng đó là một bình luận công bằng mặc dù. Nhóm của chúng tôi là tương đối nhỏ, nhưng tôi tự hỏi, nếu cơ sở mã cần phải rất lớn và kết hợp. –

+0

Nếu tôi đã phải vương miện một cách "chính", tôi chắc chắn sẽ đi với thực hiện out-of-line đồng bằng cũ (sans ảo công văn), nhưng cả hai pImpl và giao diện trừu tượng có vị trí của họ quá. Dù sao, những thứ này có thể được quản lý. Một kỹ thuật khác là có một giao diện người dùng không có khuôn mẫu cho việc khởi tạo mẫu cụ thể mà bạn muốn, với khuôn mẫu trực tiếp hỗ trợ việc triển khai ngoài dòng nhưng không hiển thị thông qua tiêu đề. Rất nhiều tùy chọn để giảm hoặc điều khiển khớp nối, cũng như các tùy chọn để tạo điều kiện dễ dàng di chuyển giữa thời gian chạy và đa hình compiletime. –

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