Как реализовать полиморфный параметр для нескольких интерфейсов?

Учитывая некоторые базовые интерфейсы A, B, C …. N

И некоторые гипотетические классы, которые реализуют их набор:

class MyClass1: public A, public B, public N;
class MyClass2: public A, public B, public D;

Я хотел бы создать функцию, которая принимает в качестве параметра объект (или указатель на объект) для класса, который включает, скажем, A и B.

void myFunc( A&B obj );

С точки зрения программиста на C ++ это кажется абсурдным. С точки зрения разработчика программного обеспечения, это кажется базовым блоком, который должен быть у всех языков.

Есть ли хитрость (кроме шаблона) или решение для этого?

Примечание: большинство интерфейсов не от меня, поэтому (в принципе) невозможно вносить изменения в интерфейсы.

Редакция:
Вот несколько примеров:

class A{
public:
virtual void draw()=0;
};

class B{
public:
virtual void edit()=0;
};class AandB: public A, public B
{
virtual void draw()override{};
virtual void edit()override{};
};

//This function know about A, B, but not AandB
void some_function((A+B)& a_and_b) { // That do not work
a_and_b.draw();
a_and_b.edit();
}

int main()
{
AandB c;
some_function(c); // that is not so easy
}

2

Решение

То, что вы действительно просите, это компилятор для создания промежуточного типа (A & B) чей интерфейс содержит оба интерфейс A а также интерфейс B, А затем разрешить любой тип, который реализует и то и другое эти интерфейсы для привязки к ссылке этого комбинированного типа.

Я даже не уверен, как вы можете ссылаться на такой гештальт-тип в синтаксисе:

void func((A+B)& var); // ???

Ну, вы можете сделать то же самое с текущим синтаксисом без компилятора, создающего леса за кулисами, просто принимая параметр дважды как это:

struct A { void stuff(){ std::cout << "A\n"; } };
struct B { void stuff(){ std::cout << "B\n"; } };
struct C { void stuff(){ std::cout << "C\n"; } };

struct MyType: A, B, C
{
void stuff() { std::cout << "MyType\n"; }
};

void func(A& a, B& b) // accept both interfaces in func
{
a.stuff(); // use interface A
b.stuff(); // use interface B
}

int main()
{
MyType m;

func(m, m); // pass both interfaces to func()
}
3

Другие решения

#include <type_traits>

using namespace std;

class A{};
class B{};

template<class T, enable_if_t<is_same<A, decay_t<T>>::value || is_same<B, decay_t<T>>::value, int> = 0>
void some_function(T&& a_or_b) {}

жить: https://godbolt.org/g/Z1MV8w

Этот пример требует c ++ 14, но вы можете использовать enable_if вместо этого, если вам нужно 11 совместимости. Это просто не так читабельно.

Если вы хотите взять что-либо, что наследуется от A или B, используйте is_base_of вместо is_same

4

Я голосовал за ответ Xaxxon,
но если вы хотите сделать это «виртуальным» способом,
Вы можете сделать класс, который расширяет A а также B,

Будет выглядеть так:

class A;
class B;
class A_B: public A, public B{
};

class MyClass1: public A_B, public XXX{
};

class MyClass2: public A_B, public YYY{
};

void myFunc( A_B obj );

Я согласен, что это выглядит подозрительно очень похоже на Java.

1

Один из способов смягчить минусы шаблона

void myFunc_impl(A& aPart, B& bPart); // aPart and bPart are from the same object.

template <typename T>
void myFunc(T& obj) {
// static_assert to have better error messages
static_assert(std::is_base_of<A, T>::value, "T should inherit from A");
static_assert(std::is_base_of<B, T>::value, "T should inherit from B");
// Forwarding to implementation
myFunc_impl(obj, obj);
}

1) заставить определение находиться в заголовке, сложно поддерживать

У вас просто есть пересылка в шапке:
код короткий.

2) сложно управлять с помощью полиморфных указателей,

Пока вы берете ссылку или указатель, эта часть в порядке с шаблоном.

4) Это затрудняет или делает невозможным некоторые другие функции, такие как виртуальные?

Действительно, метод шаблона не может быть шаблоном, но здесь вы можете перейти к виртуальному методу.

5) Код трудно проверить, так как проблемы проявляются только на этапе использования.

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

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector