C++ двойная диспетчеризация с зеркальными иерархиями

Следующие иерархии классов представляют абстрактный обработчик ресурсов и иерархии ресурсов. Оба имеют интерфейсы в качестве базовых классов. Теперь представьте, что вы пишете систему, в которой вы можете реализовать несколько конкретных систем ресурсов под этими интерфейсами. Вот только один пример. Определенный главный класс создает ресурсы, полученные из материала. Теперь, когда созданный ресурс передается базовому интерфейсу, он передается как указатель на базовый класс ресурсов, но я хочу обработать определенный ресурс и получить доступ к его конкретным атрибутам.

Я знаю о двойной отправке, но я не думаю, что это работает в этом случае. Я хотел бы предотвратить RTTI и dynamic_casts. Есть ли у вас предложения по поводу таких случаев?

class resource;

class main_resource_handler
{
public:
   virtual resource* create_resource() = 0;
   virtual void do_some(resource* st) = 0;
};

class resource
{
};

class specific_resource : public resource
{
public:
    int i;
};

class specific_resource_handler : public main_resource_handler
{
public:
    stuff* create_resource) {
        return new specific_resource);
    }
    void do_some(resource* st) {
        // in here i want to work with specific resource
    }
    void do_some(specific_resource* st) {
        // i want to get here
    }
}

main_resource_handler* handler = new specific_resource_handler();
resource* res = handler->create_resource();
handler->do_some(res); /// here

4 ответа

Я думаю, что вы не задаете правильный вопрос.

Чтобы сделать то, что вы просите, все, что вам нужно, это добавить это:

template<typename T>
class helper : public main_resource_handler
{
public:
   virtual resource* create_resource() { return new T; }
   virtual void do_some(resource* st) { do_some_specific(static_cast<T*>(st)); }
private:
   virtual void do_some_specific(T* st) = 0;
};

И измени это:

class specific_resource_handler : public helper<specific_resource>
{
private:
   virtual void do_some_specific(T* st) { ... }
}

static_cast только в том случае, если вы можете гарантировать, что вы всегда будете звонить do_some на правильный тип обработчика. Но если вы уже знаете, что это правильный тип обработчика, тогда нет необходимости вызывать метод базового класса. По-видимому, вы хотите получить какую-то resource, не зная его точного типа, передайте его соответствующему обработчику. Это сложнее...

Я задаюсь вопросом, является ли шаблон CURLYURURURING повторяющегося шаблона тем, что вы ищете. В этой теме уже есть тема о stackru.

Я не уверен, зачем вам нужен и ресурс, и обработчик - кажется, что вы подвергаете дополнительную связь чему-то, что будет инкапсулировано. Проблема не существовала бы, если бы ресурс create просто возвратил ресурс, на котором клиент мог бы напрямую вызывать методы.

Если вы хотите безопасности, пусть ресурс запомнит адрес обработчика, который его создал, а затем проверьте его в do_some(resource* st), Если ресурс был создан текущим обработчиком, и обработчик может создавать только ресурсы определенного вида, то безопасно привести его к действию и вызвать определенную функцию. Хотя, как и выше, если бы функция была просто виртуальной функцией ресурса, она была бы по определению безопасной.

Я думаю, что вы можете искать это:

http://www.artima.com/cppsource/cooperative_visitor.html

Другие вопросы по тегам