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
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.
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...
-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. –
@ AlfP.Steinbach unique_ptr? Hay chỉ là một con trỏ thô? –
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, –
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ặcbạ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.,
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 đó. –
- 1. typedefs cho các lớp templated?
- 2. bè chức năng từ một lớp templated
- 3. Chuyên ngành chức năng thành viên templated trong lớp templated
- 4. Khởi tạo các thành viên tĩnh của một lớp templated
- 5. Chuyên thành viên templated của một lớp mẫu
- 6. Thành viên riêng tư trong lớp học pimpl?
- 7. C++ rõ ràng mẫu chuyên môn của constructor templated của lớp templated
- 8. C++ - làm thế nào để thực hiện chức năng thành viên templated bên ngoài một lớp templated
- 9. Làm cách nào để sử dụng unique_ptr cho pimpl?
- 10. Pimpl + QSharedPointer - Destructor = Disaster
- 11. Quá tải toán tử nhị phân trên lớp templated
- 12. C++ Tăng serialization Serializing các lớp thừa kế templated
- 13. Truy cập biến kế thừa từ lớp cha templated
- 14. Chức năng tĩnh không có khuôn mẫu trong lớp templated
- 15. Trọng một chức năng templated với một đa hình một
- 16. chuyên môn hóa từng phần của một phương pháp trong một lớp học templated
- 17. Toán tử quá tải << đối với một lớp templated
- 18. biến thành viên Sử dụng kế thừa từ một lớp cơ sở templated (C++)
- 19. đưa chất lỏng-templated <img> một lớp trong Locomotive
- 20. Làm thế nào để kết bạn với một nhà xây dựng của lớp templated?
- 21. Phải cung cấp hàm hủy trong PIMPL
- 22. Tại sao tăng quá nhiều templated?
- 23. Làm cách nào để chuyên một thành viên tĩnh của một lớp mẫu trên một loại templated?
- 24. Thành ngữ pimpl có được sử dụng trong C# không?
- 25. Đóng ContextMenu với Menu Templated
- 26. pimpl-idiom trong mẫu; con trỏ thông minh nào?
- 27. WPF DataGrid kích thước nội dung của một cột templated
- 28. Tại sao tôi không thể gọi một phương thức templated của một lớp mẫu mà có nguồn gốc từ
- 29. Thực hiện pImpl với số lượng mã tối thiểu
- 30. lỗi Strange với một nhà điều hành templated quá tải
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