Как мне вызвать конструктор базового класса? - PullRequest
62 голосов
/ 03 августа 2011

latley Я много занимался программированием на Java. Там вы называете класс, от которого унаследованы, с super(); (вы, наверное, все это знаете)

Теперь у меня есть класс в C ++, который имеет конструктор по умолчанию, который принимает некоторые аргументы. Пример:

class BaseClass {
public:
    BaseClass(char *name); .... 

Если я унаследую класс, он выдаст мне предупреждение, что соответствующий конструктор по умолчанию недоступен. Так есть ли что-то вроде super() в C ++, или мне нужно определить функцию, где я инициализирую все переменные?

Ответы [ 6 ]

81 голосов
/ 03 августа 2011

Вы делаете это в списке инициализатора конструктора подкласса.

class Foo : public BaseClass {
public:
    Foo() : BaseClass("asdf") {}
};

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

27 голосов
/ 13 мая 2015

В заголовочном файле определите базовый класс:

class BaseClass {
public:
    BaseClass(params);
};

Затем определите производный класс как наследующий BaseClass:

class DerivedClass : public BaseClass {
public:
    DerivedClass(params);
};

В исходном файле определите конструктор BaseClass:

BaseClass::BaseClass(params)
{
     //Perform BaseClass initialization
}

По умолчанию производный конструктор вызывает только базовый конструктор по умолчанию без параметров; поэтому в этом примере конструктор базового класса НЕ вызывается автоматически при вызове производного конструктора, но этого можно достичь, просто добавив синтаксис конструктора базового класса после двоеточия (:). Определите производный конструктор, который автоматически вызывает его базовый конструктор:

DerivedClass::DerivedClass(params) : BaseClass(params)
{
     //This occurs AFTER BaseClass(params) is called first and can
     //perform additional initialization for the derived class
}

Конструктор BaseClass называется ДО конструктора DerivedClass, и те же самые / другие параметры params могут быть перенаправлены в базовый класс при желании. Это может быть вложено для более глубоких производных классов. Производный конструктор должен вызывать ТОЛЬКО ОДИН базовый конструктор. Деструкторы автоматически вызываются в обратном порядке, что и конструкторы.

РЕДАКТИРОВАТЬ: есть исключение из этого правила, если вы наследуете от любых virtual классов, обычно для достижения множественного наследования или наследования алмазов . Затем вы ДОЛЖНЫ явно вызывать базовые конструкторы всех virtual базовых классов и явно передавать параметры, в противном случае он будет вызывать только их конструкторы по умолчанию без каких-либо параметров. См .: виртуальное наследование - пропуск конструкторов

17 голосов
/ 03 августа 2011

Вы должны использовать initiailzers:

class DerivedClass : public BaseClass
{
public:
  DerivedClass()
    : BaseClass(<insert arguments here>)
  {
  }
};

Это также, как вы создаете членов вашего класса, которые не имеют конструкторов (или которые вы хотите инициализировать).Любые не упомянутые члены будут инициализированы по умолчанию.Например:

class DerivedClass : public BaseClass
{
public:
  DerivedClass()
    : BaseClass(<insert arguments here>)
    , nc(<insert arguments here>)
    //di will be default initialized.
  {
  }

private:
  NeedsConstructor nc;
  CanBeDefaultInit di;
};

Порядок, в котором указаны члены, не имеет значения (хотя конструкторы должны идти первыми), но порядок, в котором они будут построены, находится в порядке объявления.Так что nc всегда будет построено до di.

4 голосов
/ 03 августа 2011

По поводу альтернативы супер;в большинстве случаев вы используете базовый класс либо в списке инициализации производного класса, либо с помощью синтаксиса Base::someData, когда выполняете работу в другом месте, а производный класс переопределяет элементы данных.

struct Base
{
    Base(char* name) { }
    virtual ~Base();
    int d;
};

struct Derived : Base
{
    Derived() : Base("someString") { }
    int d;
    void foo() { d = Base::d; }
};
3 голосов
/ 03 августа 2011

Использовать имя базового класса в списке инициализаторов.Список инициализаторов появляется после сигнатуры конструктора перед телом метода и может использоваться для инициализации базовых классов и членов.

class Base
{
public:
  Base(char* name)
  {
     // ...
  }
};

class Derived : Base
{
public:
  Derived()
    : Base("hello")
  {
      // ...
  }
};

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

class Derived : Base
{
public:
  typedef Base super;
  Derived()
    : super("hello")
  {
      // ...
  }
};
2 голосов
/ 03 августа 2011

В C ++ нет супер (). Вы должны вызывать базовый конструктор явно по имени.

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