Каковы правила для вызова конструктора суперкласса?

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

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

632
задан Melebius 8 August 2017 в 08:35
поделиться

6 ответов

Конструкторов базового класса автоматически вызывают для Вас, если у них нет аргумента. Если Вы хотите назвать конструктора суперкласса с аргументом, необходимо использовать список инициализации конструктора подкласса. В отличие от Java, C++ поддерживает множественное наследование (что бы там ни было), таким образом, базовый класс должен быть упомянут по имени, а не "супер ()".

class SuperClass
{
    public:

        SuperClass(int foo)
        {
            // do something with foo
        }
};

class SubClass : public SuperClass
{
    public:

        SubClass(int foo, int bar)
        : SuperClass(foo)    // Call the superclass constructor in the subclass' initialization list.
        {
            // do something with bar
        }
};
[еще 114] информация о списке инициализации конструктора здесь и здесь .

857
ответ дан luke 8 August 2017 в 08:35
поделиться

В C++ конструкторов без аргументов для всех суперклассов и членских переменных вызывают для Вас, прежде, чем ввести Вашего конструктора. Если Вы хотите передать их аргументы, существует отдельный синтаксис для названного "конструктор, объединяющий в цепочку", который похож на это:

class Sub : public Base
{
  Sub(int x, int y)
  : Base(x), member(y)
  {
  }
  Type member;
};

, Если что-нибудь выполняет в этой точке броски, основаниям/участникам, которые ранее завершили конструкцию, назвали их деструкторы, и исключение повторно брошено в вызывающей стороне. Если Вы хотите поймать исключения во время объединения в цепочку, необходимо использовать функциональный блок попытки:

class Sub : public Base
{
  Sub(int x, int y)
  try : Base(x), member(y)
  {
    // function body goes here
  } catch(const ExceptionType &e) {
    throw kaboom();
  }
  Type member;
};

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

222
ответ дан Segfault 8 August 2017 в 08:35
поделиться

В C++ существует понятие списка инициализации конструктора, который является, где Вы можете и должны вызвать конструктора базового класса и где необходимо также инициализировать элементы данных. Список инициализации появляется после подписи конструктора после двоеточия, и перед телом конструктора. Скажем, у нас есть класс A:


class A : public B
{
public:
  A(int a, int b, int c);
private:
  int b_, c_;
};

Затем принимая B имеет конструктора, который берет интервал, конструктор A может быть похожим на это:


A::A(int a, int b, int c) 
  : B(a), b_(b), c_(c) // initialization list
{
  // do something
}

, Как Вы видите, конструктора базового класса вызывают в списке инициализации. Инициализация элементов данных в списке инициализации, между прочим, предпочтительна для присвоения значений для b _, и c_ в теле конструктора, потому что Вы сохраняете дополнительные расходы присвоения.

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

49
ответ дан Dima 8 August 2017 в 08:35
поделиться

Единственный способ передать значения родительскому конструктору через список инициализации. Список initilization реализован с a: и затем список классов и значений, которые будут переданы тому конструктору классов.

Class2::Class2(string id) : Class1(id) {
....
}

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

19
ответ дан CR. 8 August 2017 в 08:35
поделиться

Если у Вас будет конструктор без аргументов, то это назовут, прежде чем конструктор производного класса выполняется.

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

class base
{
  public:
  base (int arg)
  {
  }
};

class derived : public base
{
  public:
  derived () : base (number)
  {
  }
};

Вы не можете создать производный класс, не вызывая родительского конструктора в C++. То, что или происходит автоматически, если это - неаргумент C'tor, это происходит, если Вы будете звонить, то конструктор порожденного класса непосредственно как показано выше или Ваш код не скомпилируют.

19
ответ дан Mnementh 8 August 2017 в 08:35
поделиться
CDerived::CDerived()
: CBase(...), iCount(0)  //this is the initialisation list. You can initialise member variables here too. (e.g. iCount := 0)
    {
    //construct body
    }
9
ответ дан Dynite 8 August 2017 в 08:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: