铸造兄弟班有充分的理由吗?

时间:2017-05-11 08:00:37

标签: c++ polymorphism siblings static-cast

我有一个 Base 类和许多派生类(即 DerivedX )作为生产代码。 在不触及这些类的情况下,我创建了一个从Base派生的 BaseExt 类,以便为了测试目的而操纵内部数据。

+-----------+            +-----------+
| 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 个答案:

答案 0 :(得分: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);
}