首页 > 解决方案 > 在 C++ 中,对象可以与其基对象共享相同的多态成员吗?

问题描述

我有以下问题,我真的无法在标题中的一个句子中很好地描述。

我有一个简化的类层次结构,我无法更改

class Base {
  protected:
    std::vector<int> a_;

  public:
    virtual ~Base() = default;

    Base(std::vector<int> a): a_(std::move(a)) {}

    virtual void do_stuff() { /*modify a_*/ }  
};

class Derived: public Base {
  protected:
    std::vector<int> b_;

  public:
    Derived(std::vector<int> a, std::vector<int> b): Base(std::move(a)), b_(std::move(b)) {}

    void do_stuff() override {
      Base::do_stuff();
      /*modify b_*/
    }  
};

我需要向这个层次结构添加一些功能,所以我创建了一个“扩展”层次结构:

class BaseExtended {
  private:    
    Base underlying_;
    int x_;

  public:
    virtual ~BaseExtended() = default;

    BeseExtended(std::vector<int> a, int x): underlying_(std::move(a)), x_(x) {}

    virtual void do_more() { 
      underlying_.do_stuff();
      /* do more stuff according to x_ */
    }
};

class DerivedExtended: public BaseExtended{
  private:    
    Derived underlying_;
    int y_;

  public:
    DerivedExtended(std::vector<int> a, int x, std::vector<int> b, int y)
     :BaseExtended(std::move(a), x), underlying_(std::move(b)), y_(y) {}

    void do_more() override {
      BaseExtended::do_more(); 
      underlying_.do_stuff();
      /* do more stuff according to y_ */
    }
};

但这并没有做我想要的,在我调用后存储了两个向量v1v2

std::shared_ptr<BaseExtended> de = new DerivedExtended(v1, 1, v2, 2);

我不知道这是否可以在不修改原始类的情况下实现,尤其是如何在DerivedExtended中仅存储一个 vector v1副本。这可以做到吗?

标签: c++inheritancememoryconstructorpolymorphism

解决方案


解决此问题的一种方法是动态分配underlying_并具有BaseExtended派生protected类的构造函数,该构造函数Base*接受underlying_.

像这样的东西:

class BaseExtended {
...
protected:
  std::unique_ptr<Base> underlying_;

  BeseExtended(int x, std::unique_ptr<Base> underlying): underlying_(std::move(underlying)), x_(x) {}
...
};
class DerivedExtended: public BaseExtended {
...
public:
    DerivedExtended(std::vector<int> a, int x, std::vector<int> b, int y) : 
     :BaseExtended(std::make_unique<Derived>(std::move(a), std::move(b)), x), y_(y) {}

然后您可以访问(underlying_因为BaseExtended现在是protected)。

这将防止a_创建多个版本,并且在某种程度上简化了孩子的代码,这是双赢的!

请注意,您必须小心,但是,当您调用in时do_stuff(),您可能希望明确调用( ) ,否则如果覆盖则它将被调用两次(并且不会被调用)。underlying_BaseExtendedBase::do_stuff()underlying_->Base::do_suff()Deriveddo_stuff()DerivedExtended::do_more()Base::do_stuff()


推荐阅读