В C ++ может ли объект совместно использовать тот же элемент polymorphi c со своим базовым объектом? - PullRequest
0 голосов
/ 21 апреля 2020

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

У меня упрощенная иерархия классов, которую я не могу изменить

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_ */
    }
};

Но это не делало то, что я хочу, который имеет только два вектора v1 и v2 сохраняются после того, как я позвоню

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

Я не знаю, можно ли этого достичь без изменения исходных классов, особенно как хранить только один копия вектора v1 в DerivedExtended . Можно ли это сделать?

Ответы [ 2 ]

0 голосов
/ 21 апреля 2020

Один из способов решения этой проблемы - динамическое выделение 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_ создается, и это несколько упрощает код для ребенка, это выигрыш!

Обратите внимание, что вы должны быть осторожны при вызове do_stuff() на underlying_ в BaseExtended вы, вероятно, захотите определить, будет ли это явным вызовом Base::do_stuff() (underlying_->Base::do_suff()), так как в противном случае, если Derived переопределяет do_stuff(), тогда он будет вызываться дважды DerivedExtended::do_more()Base::do_stuff() не будет вызываться) .

0 голосов
/ 21 апреля 2020

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

Самым близким было бы установить владение умным указателем const на «переопределяемый» элемент «данных» в конструкторе и наличие защищенных конструкторов, позволяющих производным классам переопределять создание и тип принадлежащего объекта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...