2009-02-27 6 views
0

игнорировать это, я думал об обходном пути с использованием поколения заголовков. Это не самое приятное решение, но оно работает. Этот вопрос должен странно понимать. В основном я хочу вызвать виртуальную функцию, которая не была объявлена ​​в lib или dll, и использовать ее как обычно (но не реализовано/пустое функционирование).расширить абстрактный базовый класс без перекомпиляции источника?

У меня есть абстрактный базовый класс в моей библиотеке. Все мои плагины наследуют от него, пользовательский плагин наследует от этого класса, и его приложение использует этот класс в качестве указателя плагина. Я хочу, чтобы этот пользователь мог расширять класс и добавлять его функции. Проблема в том, что я уверен, что если он добавит виртуальную функцию и попытается ее вызвать, код будет разбит из-за того, что мои объекты не имеют дополнительных данных в своей таблице. Как я могу обойти это? Я думал о наследовании, но это привело бы к уродливым проблемам, когда третий игрок начнет играть. Я не хочу, чтобы он делал приказ для отправки расширенных функций.

Я думал о функции msg как intptr_t sendMsg (enum msgName, void * argv); Но это удаляет safty, и мне нужно будет все придумать. Какое лучшее решение для этого? Я бы скорее использовал vtables, а затем использовал функцию sendMsg. Как я могу обойти это?

+0

Вы можете написать свой код? – cbrulak

+0

Возможно, я неправильно понял вопрос, но я подумал бы, что до тех пор, пока производный класс будет создан правильно, он не потерпит крах. Не могли бы вы уточнить? – codelogic

+0

Если его код является «новым» для его класса, он будет работать нормально. (Хотя, как и кодологический, может быть, я не «получаю» вопрос.) –

ответ

1

Вы спрашиваете, если вы можете добавить виртуальные функции в базового класса без перекомпиляции? Короткий ответ на это - «нет». Долгий ответ в вашем вопросе, вам придется предоставить какой-то общий интерфейс «call_func», который позволит вам динамически вызывать функции.

1

Я думаю, что вы можете использовать регистр и механизм обратного вызова

Ваш плагин может предоставить абстрактный базовый класс «Base» и функции

Register(Base *); 

Теперь клиент может позвонить плагин Регистрация Функция

Register(b); 

, где b определяется как

Base *b = new Derived; 

где производный новый класс, производный от базы

1

Я не уверен на 100%, я вижу проблему.
Если user1 производный тип расширяет базовый класс (с большим количеством виртуальных методов), то, что должно быть хорошо (конечно, ваш код никогда не будет знать или понимать эти новые методы, но предположительно не будет называть их:

class B 
{ 
    virtual void doStuff() { /* Nothing */} 
}; 

// User 1 version: 
class U1: public B 
{ 
    virtual void doStuff() 
    { 
     this->doA(); 
     this->doB(); 
    } 
    virtual void doA() {} 
    virtual void doB() {} 
}; 

// User 2 version can extend it differently. 

Примечание:
Если вы беспокоитесь, нарезая, потому что вы храните объекты в векторе, который немного другая проблема

std::vector<B> objs; 
objs.push_back(U1()); 

std::for_each(objs.begin(),objs.end(),std::mem_fun_ref(&B::doStuff)); 

Здесь проблема в том, что определенный пользователем типа U1 не может быть скопирован в вектор. потому что вектор имеет только B объекты. Это сокращает дополнительные данные, хранящиеся в U1.

Решение этой проблемы заключается в том, что вам необходимо удерживать указатели в векторе. Это, конечно, приводит к другим проблемам безопасности исключений. Таким образом, boost имеет контейнер pte_vector <> для правильного хранения объектов, но все же позволяет использовать их как объекты.

#include <boost/ptr_container/ptr_vector.hpp> 

...... 

boost::ptr_vector<B> objs; 
objs.push_back(new U1()); 

std::for_each(objs.begin(),objs.end(),std::mem_fun_ref(&B::doStuff));