Правильный способ объявления конструктора подкласса с помощью списков инициализации и конструктора суперкласса - PullRequest
0 голосов
/ 07 ноября 2019

Моя текущая ситуация выглядит следующим образом. Это более или менее простой случай наследования, и у меня есть несколько вопросов по этому поводу.

У меня есть абстрактный класс (= он имеет чисто виртуальные функции) с двумя переменными foo_ и bar_. foo_ устанавливается параметром в конструкторе. bar_ по умолчанию должно быть 1000 для большинства подклассов, но я хочу, чтобы один конкретный класс переопределил его до 50000.

Вот фрагмент кода:

class Base {
 protected:
  const int foo_;
  const int bar_;
 public:
  Base(int foo) : foo_{foo}, bar_{1000} {}
}

class Derived : public Base {}

Во-первых, один быстрый вопрос:Лучше ли инициализировать bar_ в списке инициализации, как я делал в примере, или делать это сверху, где переменная была объявлена ​​как const int bar_{1000};?

Второй быстрый вопрос: можно ли использовать{} в списках инициализации или следует использовать ()?

Как правильно написать конструктор для класса Derived? Я хочу специально вызвать конструктор, который я определил для Base, а также использовать список инициализации, чтобы установить bar_ на 50000.

Моя идея была примерно такой:

Derived(int foo) : Base(foo), bar_{50000} {}

РЕДАКТИРОВАТЬ: После небольшой попытки я заметил, что изменение bar_ в списке конструкторов Derived, по-видимому, невозможно, потому что "bar_" is not a nonstatic data member or base class of class "Derived".

Ответы [ 2 ]

3 голосов
/ 07 ноября 2019

Лучше ли инициализировать bar_ в списке инициализации, как я делал в примере, или делать это сверху, где переменная была объявлена ​​как const int bar_ {1000};?

Это не столько о "лучшей практике", сколько о "что ты хочешь"? 1000 - начальное значение по умолчанию, которое переопределяется инициализатором в конструкторе. У вас может быть инициализатор по умолчанию и, например, один конструктор, который использует другой инициализатор, а другой - нет.

Как правильно написать конструктор для класса Derived?

Вы можете написать защищенный конструктор, который позволяет передавать оба значения:

class Base {
 protected:
  const int foo_;
  const int bar_;
  Base(int foo, int bar) : foo_(foo), bar_(bar) {}
 public:
  Base(int foo) : foo_{foo}, bar_{1000} {}
};

class Derived : public Base {
    public:
    Derived(int foo) : Base(foo,5000) {}
};
2 голосов
/ 07 ноября 2019

В этом вопросе есть много аспектов, которые необходимо решить.

Я предпочитаю инициализацию:

class Base {
 protected:
  const int foo_{};
  const int bar_{1000};
 public:
  Base(int foo) : foo_{foo} {}
}

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

По вопросу об инициализации я сдаюсь. Просто используйте руководство по стилю, которое там. (В настоящее время они, похоже, стандартизированы для использования {} повсюду) За пределами конструкторов, это еще больший беспорядок для инициализации, если вы хотите быть в ужасе от деталей, я могу порекомендовать: Николас Хосуттис "Кошмар инициализации вC ++ ".

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

class Base {
 private:
  const int foo_{};
  const int bar_{1'000};
 protected:
  Base(int foo, int bar) : foo_{foo}, bar_{bar} {}
 public:
  Base(int foo) : foo_{foo} {}
}

class Derived : public Base {
public:
    Derived(int foo) : Base{foo, 50'000} {}
}

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

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