Это очень хорошие и важные вопросы.
Относительно A:
Перед выполнением тела вашего конструктора C ++ генерирует код, который автоматически вызывает конструктор по умолчанию всех агрегированных (т.е. членских) объектов вашего класса.По сути, он преобразует следующий код:
class myClass_B {
public:
myClass_B()
{
m_instance.foo();
m_pInstance->foo();
}
private:
myClass_A m_instance;
myClass_A* m_pInstance;
};
в следующий код:
class myClass_B {
public:
myClass_B()
: m_instance()
, m_pInstance()
{
m_instance.foo();
m_pInstance->foo();
}
private:
myClass_A m_instance;
myClass_A* m_pInstance;
};
Две строки, автоматически добавленные компилятором, называются список инициализатора , он вызывает конструктор по умолчанию для каждого агрегатного объекта до того, как будет выполнено тело вашего конструктора.Обратите внимание, что второй, m_pInstance()
вызывает "конструктор по умолчанию указатель ", который создает неинициализированный указатель ;это почти всегда не то, что вы хотите.Ниже описано, как это исправить.
Теперь давайте предположим, что конструктор myClass_A
имеет подпись myClass_A(int someNumber)
, то есть он принимает аргумент.Затем C ++ не может автоматически сгенерировать список инициализатора для myClass_B
, поскольку он не знает, какое число передать конструктору myClass_A
.Он выдаст вам ошибку компилятора, вероятно, жалуясь на отсутствующий конструктор по умолчанию для myClass_A
.Вам нужно будет написать список инициализаторов самостоятельно, например:
class myClass_B {
public:
myClass_B()
: m_instance(21)
, m_pInstance(new myClass_A(21))
{
m_instance.foo();
m_pInstance->foo();
}
private:
myClass_A m_instance;
myClass_A* m_pInstance;
};
Это правильный код, который вызывает конструктор myClass_A
со значением 21 для параметра someNumber
.Здесь также показано, как правильно инициализировать указатель: сделать так, чтобы он указывал на какой-то вновь выделенный объект.
Относительно B:
В отличие от некоторых других, вы можете!(Попробуйте)
Но это приводит к неожиданному поведению, а это не то, что вам нужно.(Включая то, что он может делать то, что вы хотите, только когда планеты выровнены правильно.) Скорее всего, он рухнет, но не гарантированно рухнет.Это может привести вас к долгим отладочным ночам.Если ваш компилятор умен, он может распознать это и предупредить вас, но не выдаст ошибку.
Также обратите внимание, что для агрегатных объектов без указателя, которые имеют конструктор по умолчанию,будет вызван конструктор по умолчанию , и все будет хорошо.Проблема возникает, когда вы используете встроенные типы или указатели.Это использование неинициализированных переменных и одна из наиболее частых причин ошибки.Если ваш код делает что-то странное, всегда проверяйте, инициализировали ли вы все свои переменные.Это должно стать рефлексом для помещения записи в список инициализаторов для любой переменной-члена, даже если она вызывает конструктор по умолчанию.Все проясняет.
Относительно C:
Да.Смотрите B для деталей.Интересно то, что если метод, который вы вызываете, не использует указатель «this» (это включает в себя не использование какой-либо переменной атрибута и не вызовет метод, который использует переменную атрибута), ваш метод гарантированно будет работать.Когда вы вызываете метод для неинициализированного объекта, происходит то, что «this» объект в методе (т.е. все атрибутные переменные тоже) является случайной памятью.Код метода будет выполняться, но использовать случайную память, и это то, что не работает.
Надеюсь, это немного прояснит ситуацию.