2015-01-24 2 views
13

Я попытался найти ответ, но не уверен, что именно лучшие условия, чтобы использовать, чтобы описать это ...Я запутался об этом C++ конструктор

Я читаю книгу по программированию SFML, и один из примеры меня путают с использованием конструктора.

Допустим, что у нас есть класс A и класс B. Класс A имеет переменную-член типа B (memberB). Конструктор A выглядит следующим образом:

A::A() : OtherMemberType(with, params), memberB() 
{...} 

Учитывая, что memberB инициализируется с помощью конструктора по умолчанию в списке инициализации, что цель явно перечислить его в списке? Не было бы такого же эффекта без включения его в список?

Thanks

EDIT: Спасибо за ответы. Теперь я узнал (основную) разницу инициализации значения и инициализации по умолчанию.

Для больше контекста, так как идея «класса B может быть разорван воспитывался», вот пример кода из текста SFML Game Development:

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 «сломан», или это избыточный вызов конструктора по умолчанию?

Адам

+0

Эффект будет точно таким же. Добро пожаловать в мир C++ ... – doc

+8

@doc: Эффект будет точно таким же для некоторых типов, но с разницей, которая может вызвать неопределенное поведение для других типов. Добро пожаловать в мир C++. –

+0

@MikeSeymour, но поскольку 'memberB' является экземпляром' class B', то это не примитивный тип. C++ world ....: P – doc

ответ

14

Путем включения его в списке инициализатора, то член значение инициализирован. Если бы это было не так, это было бы default-initialized. Есть ли разница в зависимости от типа.

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

В противном случае инициализация значения инициализирует нулевые инициализирующие типы (и примитивные элементы классов), в то время как в некоторых случаях инициализация по умолчанию оставляет их неинициализированными с неопределенным значением.

UPDATE: В вашем конкретном случае класс имеет default constructor, поэтому явная инициализация избыточна.Но избыточность не обязательно является плохим - это указывает на то, что она намеренно инициализируется значением, а не просто забывается.

+0

Любопытно: изменит ли он порядок t лиги инициализируются? Может быть, он включен в список инициализатора конструктора, чтобы выразить порядок, в котором вещи инициализируются? – tenfour

+3

@tenfour: Нет, члены всегда инициализируются в порядке объявления. –

+0

Итак, предположим, что мы имеем 'struct B {int a}; struct C1 {B b; } c1; struct C2 {B b; C2(): b() {}} c2; 'Вы утверждаете, что' c2.b.a == 0', а 'c1.b.a' неопределен? –

16

Инициализация элемента в списке инициализатора value-initializes его. Опуская его из списка default-initializes it,

Если B не является агрегатом и имеет конструктор по умолчанию, нет никакой разницы.

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

Это пример, где семантика инициализации будет отличаться:

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; 
}; 
2

Учитывая то, что уже сказал Майк и хуан, я бы сказал, что B «s реализация класса нарушается тогда и только тогда он требует, чтобы быть значение инициализируется как и , если не был бы разумно ожидать, чтобы вести себя таким образом.

В целом, учитывая должным образом разработанный класс - с пользователем при условии конструктора МФЛ по умолчанию, если есть члены POD - не должна быть никакой разницы в поведении между ценностна и по умолчанию инициализации члена типа B.

Некоторых специальные классы могут не выполнять нулевую инициализацию своих членов, и у них может отсутствовать конструктор по умолчанию. std::array - один из таких классов. Они пытаются сохранить производительность исходного типа, лежащего в основе их реализации. Для членов таких классов потребуется инициализация значения.

Есть несколько возможностей:

  1. Класса B это имеет обычное поведение инициализация значения является излишней. В частности:

    а) класс B не имеет POD типизированных членов и не-POD напечатал тип членов все осуществляется в соответствии с возможностью # 1, или

    б) классом B «s написанного пользователем по умолчанию конструктор инициализирует все входящие в POD элементы.

  2. Класс B имеет семантику оптимизированного по производительности типа, такого как числовой тип или замена необработанных C-массивов. Он не имеет конструктора по умолчанию и не будет инициализироваться, если вы не выполните инициализацию значения. Пример: std::array<T>, где T - POD.

  3. Класс B является параметром шаблона. При отсутствии каких-либо ограничений на B, инициализация значений является единственным безопасным выбором. B может быть std::array, в конце концов.

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

+2

Я категорически не согласен с утверждением, что любой тип, который оставляет членов, неинициализированных, нарушен и нуждается в исправлении. Существует множество типов, таких как 'std :: array', которые не инициализируют все свои под-объекты при инициализации по умолчанию. Нулевая инициализация всех элементов большого массива занимает циклы, которые могут быть полностью избыточными из следующего, что вы делаете, явным образом каждый элемент привязывают к какому-либо другому значению. Для некоторых типов допустимый дизайн позволяет оставить данные неинициализированными по умолчанию и разрешить пользователю типа решать, является ли инициализация подходящей в данной ситуации. –

+1

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

+0

ОК, я удалил свой нисходящий поток после вашего редактирования, так как он уже не просто говорит, что все типы либо инициализируют всех участников, либо нарушаются, и допускают существование других типов: –

Смежные вопросы