у меня есть База класс и много производных классов (т.е. 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 чтобы сделать ту же работу, однако у меня есть много таких производных классов, которые добавляют слишком много кода для простой задачи.
вопрос в том
Как насчет шаблона?
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);
}
Других решений пока нет …