Подскажите, пожалуйста, что почитать по теме дизайна использующего множественное наследование интерфейсов?
Какие паттерны там применяются?
Например, как решается такая задача
class INotifiable {
public:
virtual void notify() =0;
};
class ISerializable {
public:
virtual void serialize() =0;
};
shared_ptr<INotifiable> obj = ...;
if ( obj поддерживает еще и интерфейс ISerializable ) {
сохранить obj в файл
}
Здравствуйте, Максим Рогожин, Вы писали: МР>Привет! МР>Подскажите, пожалуйста, что почитать по теме дизайна использующего множественное наследование интерфейсов?
Почитать про RTTI (run-time type identification), динамическую типизацию данных
Хотя,
Скрытый текст
МР>
МР>if ( obj поддерживает еще и интерфейс ISerializable ) {
МР> сохранить obj в файл
МР>}
МР>
МР>Просто с помощью dynamic_cast?
dynamic_cast тоже из RTTI
if (typeof(ISerializable).IsAssignableFrom(typeof(obj))) {
сохранить obj в файл
}
template <class T, class I> struct is_iface_supported : std::false_type
{
};
class A
{
};
class B
{
};
class C : public A
{
};
template <> struct is_iface_supported <C, A> : std::true_type
{
};
class D : public B
{
};
template <> struct is_iface_supported <D, B> : std::true_type
{
};
class E : public A, public B
{
};
template <> struct is_iface_supported <E, A> : std::true_type
{
};
template <> struct is_iface_supported <E, B> : std::true_type
{
};
int main()
{
A a;
B b;
C c;
D d;
E e;
if (is_iface_supported<decltype(c), A>::value) puts("c is support interface A");
if (is_iface_supported<decltype(c), B>::value) puts("c is support interface B");
if (is_iface_supported<decltype(d), A>::value) puts("d is support interface A");
if (is_iface_supported<decltype(d), B>::value) puts("d is support interface B");
if (is_iface_supported<decltype(e), A>::value) puts("e is support interface A");
if (is_iface_supported<decltype(e), B>::value) puts("e is support interface B");
return 0;
}
МР>class INotifiable {
МР>public:
МР> virtual void notify() =0;
МР>};
МР>class ISerializable {
МР>public:
МР> virtual void serialize() =0;
МР>};
МР>shared_ptr<INotifiable> obj = ...;
МР>if ( obj поддерживает еще и интерфейс ISerializable ) {
МР> сохранить obj в файл
МР>}
МР>
МР>Просто с помощью dynamic_cast?
Все операции с типами нужно производить в компайл-тайм.
if(std::is_convertible<std::decay_t<decltype(obj)>*, ISerializable*>::value) { // std::is_base_of<ISerializable, std::decay_t<decltype(obj)>>::value для прямого наследования
сохранить obj в файл
}
В С++17 можно использовать if constexpr(...), но оптимизатор и так сработает.
Здравствуйте, YuriV, Вы писали:
YV>Все операции с типами нужно производить в компайл-тайм.
YV>[ccode] YV>if(std::is_convertible<std::decay_t<decltype(obj)>*, ISerializable*>::value) { // std::is_base_of<ISerializable, std::decay_t<decltype(obj)>>::value для прямого наследования YV> сохранить obj в файл YV>}
std::decay_t<decltype(obj)>* тут лишний, мы и так знаем тип obj: INotifiable
std::is_convertible<INotifiable*, ISerializable*> ничего не знает об RTTI, так что вернёт false
Здравствуйте, Maniacal, Вы писали:
M>Эта функциональность относится к компилятору и работает на этапе компиляции. К RTTI отношения не имеет и вполне себе работает, только что проверил.
Здравствуйте, sergii.p, Вы писали:
SP>Здравствуйте, Maniacal, Вы писали:
M>>Эта функциональность относится к компилятору и работает на этапе компиляции. К RTTI отношения не имеет и вполне себе работает, только что проверил.
SP>я тоже проверил. У меня не работает https://ideone.com/rgpggr
A* в B* не конвертируется, естественно, это C* конвертируется в A* и в B*, что и нужно проверить
class A
{
};
class B
{
};
class C : public A
{
};
class D : public A, public B
{
};
int main()
{
if (std::is_convertible<C*, A*>::value) puts("C convertible to A"); // trueif (std::is_convertible<C*, B*>::value) puts("C convertible to B"); // falseif (std::is_convertible<D*, A*>::value) puts("D convertible to A"); // trueif (std::is_convertible<D*, B*>::value) puts("D convertible to B"); // truereturn 0;
}
Здравствуйте, Maniacal, Вы писали:
M>A* в B* не конвертируется, естественно, это C* конвертируется в A* и в B*, что и нужно проверить
M>
M>class A
M>{
M>};
M>class B
M>{
M>};
M>class C : public A
M>{
M>};
M>class D : public A, public B
M>{
M>};
M>int main()
M>{
M> if (std::is_convertible<C*, A*>::value) puts("C convertible to A"); // true
M> if (std::is_convertible<C*, B*>::value) puts("C convertible to B"); // false
M> if (std::is_convertible<D*, A*>::value) puts("D convertible to A"); // true
M> if (std::is_convertible<D*, B*>::value) puts("D convertible to B"); // true
M> return 0;
M>}
M>
ну а в стартовом сообщении спрашивается совсем другое. Имеем указатель на базовый класс (INotifiable) и хотим проверить, а объект, который скрывается за этим базовым классом, поддерживает ли ещё и ISerializable. Эту информацию без RTTI не получить.
SP>ну а в стартовом сообщении спрашивается совсем другое. Имеем указатель на базовый класс (INotifiable) и хотим проверить, а объект, который скрывается за этим базовым классом, поддерживает ли ещё и ISerializable. Эту информацию без RTTI не получить.
Ну или для всех интерфейсов сделать базовый интерфейс с функциями isSerializable и пр, в унаследованных реализовать возврат true/false
M>Ну или для всех интерфейсов сделать базовый интерфейс с функциями isSerializable и пр, в унаследованных реализовать возврат true/false
В одном фреймворке примерно так сделали с иерархией классов гистограмм: базовый класс это одномерные гистограммы, но при этом у них есть методы доступа к осям Y и Z. Просто для этих осей они возвращают всегда 0. Двумерные возвращают 0 в методах для Z. Ну а в трёхмерных всё реализовано.
Подскажите, пожалуйста, а есть ли минусы у такого дизайна?
class SomeClass : public ConcreteClass, // классpublic Interface1, // интерфейсpublic Interface2, // интерфейс
...
public InterfaceN // интерфейс
{
//...
};
И есть ли разница в каком порядке перечислены ConcreteClass, Interface1, ..., InterfaceN?
// Так можно? Этот вариант чем-нибудь отличается от первого варианта?class SomeClass : public Interface1, // интерфейсpublic ConcreteClass, // классpublic Interface2, // интерфейс
...
public InterfaceN // интерфейс
{
//...
};
Здравствуйте, Максим Рогожин, Вы писали:
МР>Привет!
МР>Подскажите, пожалуйста, что почитать по теме дизайна использующего множественное наследование интерфейсов? МР>Какие паттерны там применяются?
МР>Например, как решается такая задача
МР>
МР>class INotifiable {
МР>public:
МР> virtual void notify() =0;
МР>};
МР>class ISerializable {
МР>public:
МР> virtual void serialize() =0;
МР>};
МР>shared_ptr<INotifiable> obj = ...;
МР>if ( obj поддерживает еще и интерфейс ISerializable ) {
МР> сохранить obj в файл
МР>}
МР>
МР>Просто с помощью dynamic_cast?
Есть поддержка: std::dynamic_pointer_cast<ISomeInterface>(obj); // Начиная от C++11
Ну и если уже "ударять кувалдой": std::reinterpret_pointer_cast<ISomeInterface>(obj); // Начиная от C++17
Reinterpret — это на тот случай, если классы НЕ связаны отношением наследования
Здравствуйте, Kernan, Вы писали:
K>Здравствуйте, Максим Рогожин, Вы писали:
МР>>Например, как решается такая задача K>Тут надо разруливать через статический полиморфизм.
Здравствуйте, Максим Рогожин, Вы писали:
МР>Здравствуйте, Максим Рогожин, Вы писали:
МР>Подскажите, пожалуйста, а есть ли минусы у такого дизайна? МР>
МР>class SomeClass : public ConcreteClass, // класс
МР> public Interface1, // интерфейс
МР> public Interface2, // интерфейс
МР> ...
МР> public InterfaceN // интерфейс
МР>{
МР>//...
МР>};
МР>
МР>И есть ли разница в каком порядке перечислены ConcreteClass, Interface1, ..., InterfaceN? МР>
МР>// Так можно? Этот вариант чем-нибудь отличается от первого варианта?
МР>class SomeClass : public Interface1, // интерфейс
МР> public ConcreteClass, // класс
МР> public Interface2, // интерфейс
МР> ...
МР> public InterfaceN // интерфейс
МР>{
МР>//...
МР>};
МР>
Здравствуйте, Maniacal, Вы писали:
M>Здравствуйте, Максим Рогожин, Вы писали:
МР>>Привет!
МР>>Подскажите, пожалуйста, что почитать по теме дизайна использующего множественное наследование интерфейсов? M>Почитать про RTTI (run-time type identification), динамическую типизацию данных
+100500
Это, IMHO, весьма важная тема для современного C++ (хотя, есть свои достоинства и у статической типизации).