Как вызвать конструктор базового класса?
latley Я много программировал на Java. Там вы вызываете класс, который вы наследуете, с помощью super();
(все вы, вероятно, знаете это)
Теперь у меня есть класс в С++, который имеет конструктор по умолчанию, который принимает некоторые аргументы. Пример:
class BaseClass {
public:
BaseClass(char *name); ....
Если я наследую класс, он дает мне предупреждение, что нет подходящего конструктора по умолчанию. Итак, есть что-то вроде super()
в С++, или мне нужно определить функцию, где я инициализирую все переменные?
Ответы
Ответ 1
Вы делаете это в списке инициализаторов конструктора подкласса.
class Foo : public BaseClass {
public:
Foo() : BaseClass("asdf") {}
};
Конструкторы базового класса, которые принимают аргументы, должны быть вызваны там до инициализации любых элементов.
Ответ 2
В файле заголовка определите базовый класс:
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
могут быть перенаправлены в базовый класс, если это необходимо. Это может быть вложено для более глубоких производных классов. Полученный конструктор должен вызывать ТОЧНО ОДИН базовый конструктор. Деструкторы AUTOMATICALLY вызываются в порядке REVERSE, который вызывались конструкторами.
EDIT: существует исключение из этого правила, если вы наследуете от любых классов virtual
, как правило, для достижения множественного наследования или наследования алмазов. Затем вы ДОЛЖНЫ явным образом вызывать базовые конструкторы всех базовых классов virtual
и явно передавать параметры, иначе они будут вызывать только их конструкторы по умолчанию без любых параметров. См. виртуальное наследование - пропуски конструкторов
Ответ 3
Вы должны использовать 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
Относительно альтернативы супер; вы в большинстве случаев используете базовый класс либо в списке инициализации производного класса, либо используя синтаксис Base::someData
, когда вы выполняете работу в другом месте, а производный класс переопределяет данные.
struct Base
{
Base(char* name) { }
virtual ~Base();
int d;
};
struct Derived : Base
{
Derived() : Base("someString") { }
int d;
void foo() { d = Base::d; }
};
Ответ 5
Используйте имя базового класса в списке инициализаторов. Список инициализаторов появляется после сигнатуры конструктора перед телом метода и может использоваться для инициализации базовых классов и членов.
class Base
{
public:
Base(char* name)
{
// ...
}
};
class Derived : Base
{
public:
Derived()
: Base("hello")
{
// ...
}
};
Или шаблон, используемый некоторыми людьми, - это определить "супер" или "базу" самостоятельно. Возможно, некоторые люди, которые предпочитают эту технику, - это разработчики Java, которые переходят на С++.
class Derived : Base
{
public:
typedef Base super;
Derived()
: super("hello")
{
// ...
}
};
Ответ 6
В С++ нет super(). Вы должны вызвать базовый конструктор явно по имени.