В общем, мне нужен дизайн, который позволил бы некоторому классу быть виртуальным интерфейсом
Если я правильно вас понимаю, это намерение противоречит предложенному вами решению.Виртуальное наследование касается только виртуальных функций-членов.И нет никакого способа, которым вы могли бы динамически наследовать вложенные структуры, потому что это предмет лексического метапрограммирования, который не поддерживается в C ++.
Я предлагаю тщательно подумать, можете ли вы сделать свой объект неизменным.Тогда некоторая адаптация шаблона проектирования Builder / Factory позволит вам исключить использование свойств.
Вы также можете подумать о создании генератора кода.В случае, если вы выберете хорошие ключевые слова для разметки, это может быть легко.
ОБНОВЛЕНИЕ Я добавил код, чтобы уточнить мое предложение.
Прежде всего мы подготовим несколько вспомогательных объектов.Они должны быть помещены в заголовочный файл, доступный как для библиотеки, так и для клиента.Эти объекты никогда не будут изменены.
GetSetProp <> ----> IGetSetProp <----- PropFunctionAdapter </p>
template<class _Ty>
struct __declspec(novtable) IGetSetProp
{
typedef std::tr1::shared_ptr<IGetSetProp<_Ty>> ptr_t;
virtual void set_Prop(_Ty const& val);
virtual _Ty get_Prop() const;
};
template<typename _Ty>
class PropFunctionAdapter : public IGetSetProp<_Ty>
{
std::function<_Ty(void)> getter;
std::function<void(_Ty const&)> setter;
public:
PropFunctionAdapter(std::function<_Ty(void)> _getter, std::function<void(_Ty const&)> _setter)
: getter(_getter)
, setter(_setter)
{
// One may want to verify that getter and setter are not empty
}
virtual ~PropFunctionAdapter() throw() {}
inline static std::tr1::shared_ptr<typename PropFunctionAdapter<_Ty>> Create(std::function<_Ty(void)> _getter, std::function<void(_Ty const&)> _setter)
{
return std::make_shared<typename PropFunctionAdapter<_Ty>>(_getter, _setter);
}
public:
void set_Prop(_Ty const& val)
{
setter(val);
}
_Ty get_Prop() const
{
return getter();
}
};
template<class _Owner, class _Ty>
typename IGetSetProp<_Ty>::ptr_t CreateAdapter(_Owner& source, _Ty(_Owner::*getter)() const, void(_Owner::*setter)(_Ty const&))
{
return PropFunctionAdapter<_Ty>::Create(
std::tr1::bind(std::mem_fn(getter), &source),
std::tr1::bind(std::mem_fn(setter), &source, std::tr1::placeholders::_1));
}
template<class _Ty>
class GetSetProp
{
typename IGetSetProp<_Ty>::ptr_t prop;
public:
GetSetProp(typename IGetSetProp<_Ty>::ptr_t _prop)
: prop(_prop)
{
}
GetSetProp<_Ty>& operator= (_Ty const& val)
{
prop->set_Prop(val);
return *this;
}
operator _Ty() const
{
return prop->get_Prop();
}
};
Аналогичным образом вы можете определить GetProperty и SetProperty.
Предположим, у вас есть контракт данных, содержащий два поля Pressure: int и Description: string.Затем вы определяете данные контракта:
class BaseClass
{
public:
GetSetProp<int> Pressure;
GetSetProp<std::string> Description;
protected:
BaseClass(IGetSetProp<int>::ptr_t fieldA, IGetSetProp<std::string>::ptr_t fieldB)
: Pressure(fieldA)
, Description(fieldB)
{
}
virtual ~BaseClass() throw() {}
};
и его реализацию в библиотеке:
class DerivedClass : public BaseClass
{
public:
// Here you initialize fields assigning them correspondent setters and getters
// You may define an ATL-like mapping in order to hide implementation details
DerivedClass()
: BaseClass(
CreateAdapter(*this, &DerivedClass::get_Pressure, &DerivedClass::set_Pressure)
, CreateAdapter(*this, &DerivedClass::get_Description, &DerivedClass::set_Description))
{
}
virtual ~DerivedClass() throw() {}
private:
void set_Pressure(int const& value)
{
val = value;
}
int get_Pressure() const
{
return val;
}
void set_Description(std::string const& description)
{
this->description = description;
}
std::string get_Description() const
{
return description;
}
private:
int val;
std::string description;
};
// The client-side code
DerivedClass d;
BaseClass& b = d;
b.Description = "Hello";
std::string descr = b.Description;
b.Pressure = 2;
int value = b.Pressure;