2012-06-24 27 views
5

Tôi đang cố gắng viết một ứng dụng đang tải các phần mở rộng của nó một cách năng động trong suốt thời gian chạy. Tôi đã sử dụng thư viện Preprocessor Boost để viết một hàm tiền xử lý, đưa ra một danh sách các tên, khai báo một lớp cho mỗi tên (và làm cho tất cả các lớp con của một số lớp AbstractPlugin) và sau đó khai báo một trình tự Boost MPL chứa các lớp đó. Sau đó, tôi đã viết một lớp cố gắng trỏ đến AbstractPlugin nếu nó có thể được truyền tới bất kỳ kiểu nào trong chuỗi MPL đó. Vấn đề ở đây là chức năng tiền xử lý của tôi cần một danh sách đầy đủ tất cả các phần mở rộng mà tôi muốn tạo và tải. Có một số kỹ thuật cho phép tôi đăng ký từng phần mở rộng trong một tệp riêng biệt không?Đăng ký lớp C++ sao cho sau này một hàm có thể lặp qua tất cả các lớp đã đăng ký

Cập nhật:

Tôi tin rằng, giải thích của tôi về tình hình quá mơ hồ, vì vậy tôi quyết định làm cho nó cụ thể hơn.

Tôi muốn xác định tập hợp các loại tiện ích mở rộng. Đối với mỗi loại tiện ích, có thể có bất kỳ số lượng tiện ích mở rộng nào. Trong thời gian chạy chương trình tải thư viện bên ngoài, giải quyết các chức năng điểm nhập cảnh, gọi nó và, kết quả là, có được một con trỏ. Sau đó, nó cố gắng đưa con trỏ đó tới tất cả các kiểu mở rộng đã đăng ký (sử dụng dynamic_cast, vì vậy các lớp cho các kiểu mở rộng đều được thừa kế từ một số lớp cơ sở đa hình). Nếu dàn diễn viên cho một số loại tiện ích mở rộng thành công, con trỏ được đúc sẽ được sử dụng trong một cuộc gọi đến trình xử lý đặc biệt cho loại tiện ích mở rộng đó.

Số loại tiện ích được biết tại thời gian biên dịch (trong khi, rõ ràng, số lượng tiện ích là vô hạn). Sử dụng aproach của tôi lớp bộ nạp sử dụng kiến ​​thức này để kiểm tra xem có tồn tại một trình xử lý cho từng loại tiện ích (nếu không, chương trình không biên dịch). Ngoài ra, aproach của tôi không buộc các lớp học cho các loại mở rộng biết bất cứ điều gì về bộ nạp (vì vậy nó rất dễ dàng để sửa đổi bộ tải). Nhưng sẽ thuận tiện hơn nếu mỗi loại tiện ích mở rộng đăng ký chính nó.

+0

Tạo tiêu đề có thể chấp nhận được không? – Arpegius

Trả lời

0

Khi nó quay ra những gì tôi muốn là không thể. Lý do cho điều đó là "đăng ký" trong ngữ cảnh này có nghĩa là "đặt một loại kiểu chuỗi bên trong" và các chuỗi kiểu là không thay đổi bởi vì chúng là các kiểu của chúng. Vì vậy, một trong hai nên tạo trình tự loại này theo cách thủ công hoặc khi một số người đề xuất di chuyển "đăng ký" vào thời gian chạy.

0

Không khó để triển khai khung công tác mở rộng như vậy bằng cách sử dụng mẫu nhà máy trừu tượng.

http://en.wikipedia.org/wiki/Abstract_factory_pattern

Bạn có thể đăng những trừu tượng chức năng nhà máy/đối tượng trong một danh sách toàn cầu, và làm bất cứ điều gì bạn muốn làm cơ sở trên đó.

8

Bạn có thể làm cho tất cả các lớp của bạn tự đăng ký trong một số loại bộ sưu tập. Dưới đây là một cách tiếp cận bộ xương:

Base.hpp:

#include <memory> 
#include <unordered_map> 
#include <string> 

struct Base 
{ 
    virtual ~Base() = default; 

    using create_f = std::unique_ptr<Base>(); 

    static void registrate(std::string const & name, create_f * fp) 
    { 
     registry()[name] = fp; 
    } 

    static std::unique_ptr<Base> instantiate(std::string const & name) 
    { 
     auto it = registry().find(name); 
     return it == registry().end() ? nullptr : (it->second)(); 
    } 

    template <typename D> 
    struct Registrar 
    { 
     explicit Registrar(std::string const & name) 
     { 
      Base::registrate(name, &D::create); 
     } 
     // make non-copyable, etc. 
    }; 

private: 
    static std::unordered_map<std::string, create_f *> & registry(); 
}; 

Base.cpp:

#include "Base.hpp" 

std::unordered_map<std::string, Base::create_f *> & Base::registry() 
{ 
    static std::unordered_map<std::string, Base::create_f *> impl; 
    return impl; 
} 

Bây giờ sử dụng điều này trong một khách hàng:

nguồn gốc. hpp:

#include "Base.hpp" 

struct Derived : Base 
{ 
    static std::unique_ptr<Base> create() { return std::make_unique<Derived>(); } 
    // ... 
}; 

Derived.cpp:

#include "Derived.hpp" 

namespace 
{ 
    Base::Registrar<Derived> registrar("MyClass"); 
} 

Các constructor của Base::Registrar<Derived> sẽ chăm sóc của đăng ký lớp Derived dưới cái tên "MyClass".Bạn có thể tạo thể hiện của Derived động qua:

std::unique_ptr<Base> p = Base::instantiate("MyClass"); 

Mã này có thể/nên được cải thiện bằng cách phát hiện đăng ký lại, in một danh sách các lớp có sẵn, vv Lưu ý cách chúng ta tránh bất kỳ vấn đề khởi tạo đặt tĩnh khiến tôi thực tế đăng ký bản đồ đối tượng một khối-tĩnh đối tượng, được đảm bảo để được khởi tạo trước khi sử dụng đầu tiên của nó, và do đó bị phá hủy chỉ sau khi sử dụng cuối cùng của nó.

+0

Tôi đã xem xét một cái gì đó như thế này, nhưng tôi quan tâm nhiều hơn trong một aproach biên dịch thời gian. Tôi không chắc chắn rằng có tồn tại một, nhưng vẫn còn, đất của C++ mẫu là đầy đủ các phép lạ. – grisumbras

+0

Không có tĩnh. Bạn không thể tạo các lớp tự đăng ký chúng, vì mỗi tệp thực thi có đơn vị biên dịch riêng và mỗi lớp có thể được đặt trong thư viện khác nhau. Sức mạnh của giải pháp này là khi bạn tải một thư viện động, lớp mở rộng đã trở thành tự động có sẵn. Nó nổi tiếng và rất hữu ích. – Arpegius

+0

Đây là một thực hiện rất tốt đẹp. Điều duy nhất tôi không hiểu là = 0 trên hàm static create(). Theo tôi biết đó là C++ không hợp lệ vì các hàm tĩnh không bao giờ có thể là ảo. Phần đó phải làm việc như thế nào? – Shenjoku

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