2011-10-22 31 views
11

Tôi muốn sử dụng thành ngữ pimpl để tránh việc người dùng thư viện của mình cần phụ thuộc bên ngoài của chúng ta (như tăng, vv), tuy nhiên khi lớp của tôi được tạo khuôn mẫu. tiêu đề. Có cái gì tôi có thể làm thay vào đó?pimpl cho một lớp templated

Trả lời

7

Nếu lớp được sắp xếp, người dùng của bạn về cơ bản cần biên dịch nó (và điều này đúng theo nghĩa đen trong các triển khai C++ được sử dụng rộng rãi nhất) và vì vậy họ cần phụ thuộc bên ngoài của bạn.

Giải pháp đơn giản nhất là đặt phần lớn việc triển khai lớp của bạn vào một lớp cơ sở không phải mẫu (hoặc đối tượng thành viên được đóng gói của một số lớp). Giải quyết vấn đề ẩn mô-đun ở đó.

Sau đó viết mẫu có nguồn gốc (hoặc kèm theo) lớp để thêm loại an toàn cho nó.

Ví dụ, giả sử bạn có một mẫu mà cung cấp khả năng tuyệt vời để phân bổ về tiếp cận đầu tiên (bỏ qua constructor sao chép cần thiết, chuyển nhượng, destructor):

template <class T> 
class MyContainer 
{ 
    T *instance_; 

public: 
    MyContainer() : instance_(0) {} 

    T &access() 
    { 
     if (instance_ == 0) 
      instance_ = new T(); 

     return *instance_; 
    } 
}; 

Nếu bạn muốn "logic" được tách thành lớp không phải mẫu cơ sở, bạn phải tham số hóa hành vi theo cách không phải mẫu, tức là sử dụng các chức năng ảo:

class MyBase 
{ 
    void *instance_; 

    virtual void *allocate() = 0; 

public: 
    MyBase() : instance_(0) {} 

    void *access() 
    { 
     if (instance_ == 0) 
      instance_ = allocate(); 

     return instance_; 
    } 
}; 

Sau đó, bạn có thể thêm nhận thức kiểu ở lớp ngoài:

template <class T> 
class MyContainer : MyBase 
{ 
    virtual void *allocate() 
     { return new T(); } 

public: 
    T &access() 
     { return *(reinterpret_cast<T *>(MyBase::access())); } 
}; 

tức là bạn sử dụng chức năng ảo để cho phép mẫu điền "các hoạt động phụ thuộc vào loại. Rõ ràng mô hình này sẽ chỉ thực sự có ý nghĩa nếu bạn có một số logic kinh doanh đó là giá trị nỗ lực của ẩn.

+0

Tôi nghĩ rằng phương pháp này có thể cũng hữu ích nếu bạn không muốn định nghĩa preprocessor của bạn ('# define'), hằng vv để được hiển thị. Là một nhà phát triển, tôi không muốn xem chi tiết triển khai của lớp/thư viện mà tôi đang sử dụng, đặc biệt là trong danh sách tự động hoàn tất. Bạn có thể muốn ẩn chúng ngay cả khi logic nghiệp vụ của bạn không đáng để ẩn. – mostruash

1

Bạn có thể nhanh chóng khởi tạo mẫu trong tệp nguồn, nhưng điều đó chỉ có thể xảy ra nếu bạn biết loại mẫu sẽ là gì. Nếu không, không sử dụng thành ngữ pimpl cho mẫu.

Something như thế này:

header.hpp:

#ifndef HEADER_HPP 
#define HEADER_HPP 

template< typename T > 
class A 
{ 
    // constructor+methods + pimpl 
}; 

#endif 

source.cpp:

#include "header.hpp" 

// implementation 

// explicitly instantiate for types that will be used 
template class A<int>; 
template class A<float>; 
// etc... 
+0

-1 Không sử dụng 'auto_ptr' cho PIMPL (đó là ** hành vi chưa xác định ** để khởi tạo' auto_ptr' với kiểu không đầy đủ). Nó hoạt động nếu bạn định nghĩa cả hàm tạo và hàm hủy cho lớp bên ngoài. Nhưng trong trường hợp đó bạn không cần một con trỏ thông minh. –

+0

@ AlfP.Steinbach unique_ptr? Hay chỉ là một con trỏ thô? –

+1

Có, cả hai OK (mặc dù tôi không chắc chắn về các chi tiết về cách sử dụng 'unique_ptr' trong trường hợp này; tôi sẽ chỉ sử dụng' shared_ptr' và chấp nhận phí trên không làm cho mọi người đọc in đẹp trong Tiêu chuẩn). Chúc mừng, –

1

Có hai giải pháp chung:

  • trong khi giao diện phụ thuộc vào tôi nhập T, nó sẽ hoạt động để triển khai một cách yếu kém hơn (ví dụ: một bằng cách sử dụng con trỏ void* trực tiếp hoặc xóa lỗ), hoặc

  • bạn chỉ hỗ trợ một số loại cụ thể và khá giới hạn.

Giải pháp thứ hai có liên quan, ví dụ: char/wchar_t công cụ độc lập.

Giải pháp đầu tiên khá phổ biến trong những ngày đầu của mẫu C++, vì lúc đó các trình biên dịch không tốt trong việc nhận ra sự tương đồng trong mã máy được tạo và giới thiệu mã số “ bloat ”. Ngày nay, nhiều bất ngờ của bất kỳ người mới nào đã thử nó, một giải pháp được tạo khuôn mẫu thường có thể có dấu chân mã máy nhỏ hơn một giải pháp dựa trên tính đa hình thời gian chạy. Tất nhiên, YMMV.

Cheers & h.,

+0

Chỉnh sửa đã cố gắng của người nào đó đã đề xuất xóa "công cụ xóa trực tiếp hoặc loại bỏ" và "cụ thể và ..." trình độ chuyên môn. Việc xây dựng là cần thiết cho ý nghĩa, và trình độ là cần thiết cho sự chính xác. Câu trả lời được chấp nhận là giải pháp hiện tại là một ví dụ về "trực tiếp". Hiện chưa có ví dụ về "loại tẩy xoá", và chỉ đề cập đến trong câu trả lời này; nó sẽ là một sự xấu hổ nếu ai đó đã thành công trong việc xóa bỏ điều đó. –

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