Кастинг братьев и сестер с уважительной причиной?

у меня есть База класс и много производных классов (т.е. DerivedX) как производственный код.
Не касаясь этих классов, я делаю BaseExt класс, производный от Base для манипулирования внутренними данными в целях тестирования.

+-----------+            +-----------+
| Base      + <- - - - - | BaseExt   |
+-----------+            +-----------+
/|\
|
+-----------+
| DerivedX  +
+-----------+

Вот пример кода

      class Base {
public:
int data() const { return _data; }
protected:
Base() = default;
virtual ~Base() = default;
int _data;
};

class Derived1 : public Base {
};

class BaseExt : public Base {
public:
void inject_data(int data) { _data = data; }
};

Это работает для меня интуитивно.

    std::shared_ptr<Base> p = std::make_shared<Derived1>();
auto d1 = p->data(); // 0
std::static_pointer_cast<BaseExt, Base>(p)->inject_data(10);
auto d2 = p->data(); // 10

Базовый уровень: я не хочу менять свой производственный код (т.е. Base и DerivedX)

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

вопрос в том

  • Разумно ли привести в родной класс для этого случая использования?
  • как сделать это безопасно? (например, нет атрибута в классе родного брата)
  • любое лучшее и лаконичное решение (кроме изменения классов Base и DereivedX)

1

Решение

Как насчет шаблона?

template<typename T>
struct TestableDerived : T {

inject_data(int data) {
_data = data;
}

static std::shared_ptr<Base> createAndInjectData(int data) {
std::shared_ptr<TestableDerived<T>> ptr = std::make_shared<TestableDerived<T>>();
ptr->inject_data(data);
return ptr;
}
}

В качестве альтернативы, если вы готовы изменить свой источник так, чтобы каждый производный класс фактически наследовал от Base (Т.е. class DerivedX : public virtual Base), тогда я думаю, что вы можете смешать это с множественным наследованием, чтобы просто получить «дополнительный метод во время тестирования» (я не проверял это):

struct BaseExt : virtual Base {
void inject_data(int data) { _data = data; }
}

template<typename T>
struct TestDerived<T> : virtual T, virtual BaseExt {}

void doSomeTesting() {
std::shared_ptr<TestDerived<DerivedX>> p1 = std::make_shared<TestDerived<DerivedX>>();
std::shared_ptr<DerivedX> p2 = p1;
std::shared_ptr<BaseExt> p3 = p1;

assert(p1->data()==0);
assert(p2->data()==0);
assert(p3->data()==0);

p3->inject_data(10);

assert(p1->data()==10);
assert(p2->data()==10);
assert(p3->data()==10);
}
1

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

Других решений пока нет …

По вопросам рекламы [email protected]