Рефакторинг класса, унаследованного от std :: container - PullRequest
0 голосов
/ 12 марта 2012

У меня средний кусок кода, содержащий 5 классов, которые все они унаследованы от стандартных контейнеров.Например:

class Step : public std::vector<unsigned int>
{
public:
    friend std::ostream& operator<<(std::ostream& outStream, const Step& step);
    Step& operator =(const Step& rhv);
    static Step fromString(const std::string &input);
    std::string name;
};

Я знаю, что наследовать от стандартных контейнеров плохая идея, поэтому я собираюсь удалить все наследования, добавив подобъект родительского типа данных:

class Step
{
public:
    friend std::ostream& operator<<(std::ostream& outStream, const Step& step);
    Step& operator =(const Step& rhv);
    static Step fromString(const std::string &input);
    std::string name;
    // std::vector interface:
    inline std::vector<unsigned int>::const_iterator begin() const {return data.begin();}
    inline std::vector<unsigned int>::const_iterator end() const {return data.end();}
    inline size_t size() const {return data.size();}
    typedef std::vector<unsigned int>::const_iterator const_iterator;
private:
    std::vector<unsigned int> data;
};

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

И вопрос: что вы предлагаете пересмотреть код небольшими изменениями?(как можно меньше)

Уточнение: У меня есть несколько классов, унаследованных от контейнеров stl.И есть много кодов, использующих их.Мой вопрос заключается в том, как я могу удалить это злое наследство, не меняя коды с помощью этих классов?

Ответы [ 4 ]

4 голосов
/ 12 марта 2012

Я знаю, что плохая идея наследовать от стандартных контейнеров

Это имеет смысл во многих сценариях.Если вы думаете, что это всегда плохая идея, то вы ошибаетесь.Если наследование от стандартного контейнера делает ваш код коротким и его легче читать, тогда хорошая идея - наследовать от STL-контейнера.По MY мнению, ваш первый класс (который наследует std :: vector) лучше второго.

И вопрос: что вы предлагаете пересмотреть код небольшими изменениями?

Если вы хотите потратить свое время просто на это ...

Для начала вы можете удалить функцию "общедоступный друг", которая не имеет никакого смысла.

После этого объявите несколько typedefs.

typedef std::string Name;

class Step{
protected:
    typedef std::vector<int> Data;
    Data data;
public:
    typedef Data::const_iterator ConstIterator;
    Step& operator=(const Step& other);
    static Step fromString(const std::string &input);
    Name name;
    ConstIterator begin() const;
    ConstIterator end() const;
    size_t size() const;
};

И используйте эти typedeffed типы во всем коде, который взаимодействует с Step.Таким образом, вы сможете позже изменить внутренние типы (например, заменить std :: vector на std :: deque или реализовать собственный класс итератора) без необходимости изменения всего проекта.

2 голосов
/ 12 марта 2012

Одно из возможных решений: сделать наследство частным (или защищенным, если оно имеет смысл) и using соответствующих членов:

class Step : private std::vector<int>
{
    typedef std::vector<int> base_;

public:
    using base_::operator[];
    using base_::size;
    ...

};

Если наследование действительно упростило код, то вам может понравитьсяэто решение.Реальная проблема с наследованием от контейнеров состоит в том, что преобразование в vector может создать вам проблемы, когда вы добавите членов в класс Step: деструктор изменится, и вы знаете, что он не виртуален.Частное наследство решает эту проблему.

1 голос
/ 12 марта 2012

Лучшим решением было бы сначала изменить вашу функциональность как бесплатные функции:

namespace Step2 {
  std::vector<unsigned int> fromString(const std::string &input);
}

и затем предоставьте автономный заголовок для старого API:

  DEPRECATED class Step : public std::vector<unsigned int>
  {
    public:
    inline static Step fromString(std::string const& input);
    {
      return Step(Step2::fromString(input));
    }
  };
0 голосов
/ 12 марта 2012
typedef std::vector<unsigned int> data_t;
data_t data;

Введение typedef упрощает всю сигнатуру методов и снижает риск изменения типа вектора

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