2011-12-23 27 views
9

Tôi đang cố gắng tạo lớp quản lý cấu hình, có thể lưu trữ các đối tượng tùy ý bằng chuỗi std ::.Bất kỳ cách nào để có một chức năng mẫu trong một lớp cơ sở trừu tượng?

khởi đầu ý tưởng của tôi cho giao diện của tôi (trừu tượng lớp cơ sở) là này (tất nhiên đây là khủng khiếp không đầy đủ)

class ConfigurationManager 
{ 
public: 
    static boost::shared_ptr<ConfigurationManager> create(); 

    template<typename T> 
    virtual T getOption(const std::string& name) = 0; 
}; 

Nhưng sau đó trình biên dịch của tôi chỉ ra rằng mẫu của không thể ảo (và sau đó tôi nhận ra rằng tôi không thể có các mẫu đã xuất).

Nội bộ Tôi sẽ sử dụng boost :: any's (khá nhiều thời gian chạy kiểm tra void *), nhưng tôi không muốn để lộ tăng :: bất kỳ trong giao diện của tôi.

Cách tốt nhất để thực hiện việc này là gì?

+1

Để đi về những gì, chính xác? –

+0

@Oli Để mô phỏng giao diện cú pháp không thể mà tôi đã đăng trong câu hỏi của mình. – Lalaland

+0

Vì vậy, bạn muốn làm các mẫu chức năng đa hình, mặc dù chúng không thực sự khả thi? –

Trả lời

7

Làm cho chức năng trừu tượng ảo được bảo vệ trở về boost::any và chức năng mẫu công khai, không trừu tượng, công khai để ẩn nó khỏi người dùng giao diện của bạn.

class ConfigurationManager { 
protected: 
    virtual boost::any getOptionProtected(const std::string& name) = 0; 
public: 
    static boost::shared_ptr<ConfigurationManager> create(); 
    template<typename T> T getOption(const std::string& name) { 
     return boost::any_cast<T>(getOptionProtected(name)); 
    } 
}; 
+0

Đó phải là 'boost :: any_cast (getOptionProtected (name));' – Xeo

+0

@Xeo cảm ơn vì đã sửa! (bạn có thể nói rằng tôi không bao giờ sử dụng tăng chỉ từ một dòng). – dasblinkenlight

+0

Đã kết thúc bằng cách sử dụng gần như chính xác điều này. – Lalaland

4

Một cách tiếp cận thay thế sẽ được vượt qua tên của các loại có nguồn gốc để ConfigurationManager:

template<typename Derived> 
class ConfigurationManager 
{ 
    public: 
    static boost::shared_ptr<ConfigurationManager> create(); 

    template<typename T> 
    T getOption(const std::string& name) 
    { 
    // call Derived::getOption 
    return static_cast<Derived*>(this)->getOption(name); 
    } 
}; 

Các loại có nguồn gốc Foo sau đó sẽ được xác định như thế này:

class Foo : public ConfigurationManager<Foo> 
{ 
    template<typename T> 
    T getOption(const std::string& name) 
    { 
    // do something Foo-specific here 
    } 
}; 

Sự kết thúc kết quả là một cái gì đó tương tự như một chức năng ảo trừu tượng. Thành ngữ này được gọi là curiously recurring template pattern.

+1

Tôi biết điều này là cũ, nhưng điểm của lớp ConfigurationManager trong việc sử dụng CRTP này là gì? Chúng tôi không thể sử dụng loại đó để lưu trữ Foo. – Constantin

1

Tôi không biết những gì boost::any làm cho bạn, nhưng bên cạnh đó lựa chọn của bạn (chỉ, tôi nghĩ) là một trong hai 1) Hãy ConfigurationManager một lớp mẫu, hoặc 2) làm ConfigurationManager::getOptionphi Virtual nhưng sử dụng một chức năng ảo không phải mẫu riêng biệt (được gọi trong phạm vi getOption) quản lý chức năng bạn muốn trong các lớp dẫn xuất của bạn. Cũng có các biến thể trên 2), chẳng hạn như bao gồm một con trỏ tới một đối tượng chỉ định chức năng dự định của (không ảo) getOption. Đối tượng này sẽ là một thể hiện của một lớp mà chính nó là một phần của một hệ thống phân cấp thừa kế - về cơ bản là mô hình Chiến lược. Có vẻ phức tạp hơn. Vì vậy, về cơ bản tôi gợi ý

class ConfigurationManager 
{ 
    public: 
     ... 
     template<typename T> 
     getOption(...); 
    private: 
     virtual getOptionSpecial(...) = 0; //Called within getOption 
}; 

Câu trả lời trên xuống this SO thread là (một phần) tại sao tôi nghĩ rằng đây là khá nhiều tất cả các bạn có thể làm.

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