Я запутался в этом конструкторе С++
Я попытался найти ответ, но не уверен, что наилучшим образом использовать его для описания...
Я читаю книгу о программировании SFML, и один из примеров меня смутил с использованием конструктора.
Допустим, что у нас есть класс A и класс B. Класс A имеет переменную-член типа B (memberB). Конструктор для A выглядит так:
A::A() : OtherMemberType(with, params), memberB()
{...}
Учитывая, что memberB инициализируется конструктором по умолчанию в списке инициализации, какова цель явного перечисления его в списке? Не был бы такой же эффект без включения его в список?
Спасибо
EDIT: Спасибо за ответы. Теперь я узнал (основную) разницу инициализации значения и инициализации по умолчанию.
Для большего контекста, поскольку идея "класс B может быть сломана, была поднята", вот пример кода из текста Разработка игры SFML:
class Game
{
public:Game();
void run();
private:
void processEvents();
void update();
void render();
private:
sf::RenderWindow mWindow;
sf::CircleShape mPlayer;
};
Game::Game()
: mWindow(sf::VideoMode(640, 480), "SFML Application")
, mPlayer()
{
mPlayer.setRadius(40.f);
mPlayer.setPosition(100.f, 100.f);
mPlayer.setFillColor(sf::Color::Cyan);
}
Итак, в этом контексте кто-нибудь знает некоторые особенности SFML? Is sf:: CircleShape "сломан", или это избыточный вызов конструктора по умолчанию?
Адам
Ответы
Ответ 1
Включив его в список инициализации, элемент инициализируется значением. Если бы это не так, это было бы инициализировано по умолчанию. Существует ли разница в типе.
Если это тип класса с объявленным конструктором по умолчанию, то нет никакой разницы: этот конструктор будет использоваться в любом случае.
В противном случае инициализация значения будет инициализировать нулевые примитивные типы (и примитивные элементы классов), в то время как в некоторых случаях инициализация по умолчанию оставит их неинициализированными с неопределенным значением.
UPDATE: В вашем конкретном случае класс имеет конструктор по умолчанию, поэтому явная инициализация избыточна. Но избыточность не обязательно является плохим - это указывает на то, что она намеренно инициализируется значением, а не просто забывается.
Ответ 2
Инициализация члена в списке инициализаторов значение инициализирует его. Опустив его из списка default-initializes,
Если B
является неагрегатом и имеет конструктор по умолчанию, нет никакой разницы.
Если B
- совокупность, то может быть разница. инициализация по умолчанию означает, что если он содержит встроенные модули, они не могут быть инициализированы. инициализация значения в конечном итоге приведет к нулевой инициализации его членов.
Это пример, где семантика инициализации будет различной:
struct B
{
int i, j, k;
};
struct A
{
A() : b() {} // value-initializes b: b.i, b.j, b.k zero initialized
B b;
};
struct AA
{
AA() {} // default-initializes b: b.i, b.j, b.k have no initialization
B b;
};
Ответ 3
Учитывая то, что сказал майк и юань, я бы сказал, что реализация класса B
нарушена, если для этого требуется инициализация значений таким образом, если не будет разумно ожидать, что она будет вести себя таким образом.
Как правило, с учетом правильно спроектированного класса - с предоставленным пользователем конструктором по умолчанию iff, если есть члены POD - не должно быть разницы в поведении между инициализацией значения и инициализации по умолчанию членом типа B.
Некоторые специальные классы могут не выполнять нулевую инициализацию своих членов, и у них может отсутствовать конструктор по умолчанию. std::array
- один из таких классов. Они пытаются сохранить производительность исходного типа, лежащего в основе их реализации. Для членов таких классов потребуется инициализация значения.
Существует несколько возможностей:
-
Класс B
имеет обычное поведение, инициализация значения является излишней. В частности:
a) класс B
не имеет элементов, набранных POD, и типы типизированных типов, отличных от POD, все реализованы в соответствии с возможностью # 1 или
b) class B
пользовательский конструктор по умолчанию инициализирует все элементы, набранные POD, по мере необходимости.
-
Класс B
имеет семантику оптимизированного по производительности типа, такого как числовой тип или замена для исходных массивов C. Он не имеет конструктора по умолчанию и не будет инициализироваться, если вы не выполните инициализацию значения. Пример: std::array<T>
где T
- POD.
-
Класс B
является параметром шаблона. При отсутствии каких-либо ограничений на B
инициализация значений является единственным безопасным выбором. B
может быть std::array
, в конце концов.
-
Класс B
не работает. Его члены будут правильно инициализированы, если его экземпляры инициализируются значением. Он должен быть исправлен.