Budowa jest dość trudnym tematem w C++. Prosta odpowiedź to to zależy od. To, czy Foo zostanie zainicjowany, zależy od definicji samego Foo. O drugie pytanie: jak sprawić, aby Bar inicjował Foo: list inicjalizacji są odpowiedzią.
Podczas gdy ogólna zgoda jest taka, że Foo będzie domyślnie inicjowane przez niejawny domyślny konstruktor (wygenerowany przez kompilator), który nie musi mieć wartości true.
Jeśli Foo nie ma zdefiniowanego przez użytkownika konstruktora domyślnego, wówczas Foo nie będzie inicjowane. Aby być bardziej precyzyjnym: każdy członek Bar lub Foo brakuje domyślnego konstruktora zdefiniowany przez użytkownika zostaną niezainicjowanymi przez kompilator generowane domyślnego konstruktora barskiej:
class Foo {
int x;
public:
void dump() { std::cout << x << std::endl; }
void set() { x = 5; }
};
class Bar {
Foo x;
public:
void dump() { x.dump(); }
void set() { x.set(); }
};
class Bar2
{
Foo x;
public:
Bar2() : Foo() {}
void dump() { x.dump(); }
void set() { x.set(); }
};
template <typename T>
void test_internal() {
T x;
x.dump();
x.set();
x.dump();
}
template <typename T>
void test() {
test_internal<T>();
test_internal<T>();
}
int main()
{
test<Foo>(); // prints ??, 5, 5, 5, where ?? is a random number, possibly 0
test<Bar>(); // prints ??, 5, 5, 5
test<Bar2>(); // prints 0, 5, 0, 5
}
Teraz, jeśli Foo miał konstruktor zdefiniowanej przez użytkownika to byłoby być inicjowane zawsze, niezależnie od tego, czy Bar ma zainicjowany konstruktor, czy nie. Jeśli Bar ma zdefiniowany przez użytkownika konstruktor, który jawnie wywołuje (prawdopodobnie niejawnie zdefiniowany) konstruktor Foo, to w rzeczywistości Foo zostanie zainicjowany. Jeśli lista inicjalizacji paska nie wywoła konstruktora Foo, będzie to odpowiednik przypadku, w którym Bar nie ma konstruktora zdefiniowanego przez użytkownika.
Kod testowy może wymagać wyjaśnienia. Interesuje nas, czy kompilator zainicjalizuje zmienną bez kodu użytkownika, który faktycznie wywołuje konstruktor. Chcemy sprawdzić, czy obiekt jest zainicjowany, czy nie. Teraz, jeśli po prostu utworzymy obiekt w funkcji, może się zdarzyć, że znajdzie się w nienaruszonej pozycji pamięci zawierającej już zera. Chcemy odróżnić szczęście od sukcesu, więc definiujemy zmienną w funkcji i wywołujemy funkcję dwukrotnie. W pierwszym uruchomieniu wydrukuje zawartość pamięci i wymusi zmianę. W drugim wywołaniu funkcji, ponieważ ślad stosu jest taki sam, zmienna będzie utrzymywana w dokładnie tej samej pozycji pamięci. Jeśli został zainicjowany, byłby ustawiony na 0, w przeciwnym razie zachowałby tę samą wartość, co poprzednia zmienna w dokładnie tej samej pozycji.
W każdym z przebiegów testowych pierwsza drukowana wartość jest wartością początkową (jeśli została faktycznie zainicjowana) lub wartością w tej pozycji pamięci, która w niektórych przypadkach wynosi 0. Druga wartość to tylko test token reprezentujący wartość w pozycji pamięci po ręcznej jej zmianie. Trzecia wartość pochodzi z drugiego uruchomienia funkcji. Jeśli zmienna jest inicjalizowana, spadnie z powrotem do 0. Jeśli obiekt nie zostanie zainicjowany, jego pamięć zachowa starą zawartość.
Jestem zaznajomiony z C++ i ciągle mam pewne wątpliwości w tym zakresie. Co więcej, większość odpowiedzi wyraźnie stwierdza, że domyślny konstruktor Foo zostanie wywołany, a faktem jest, że zależy to od definicji samego Foo. Czy jest to domyślny konstruktor dostarczony przez użytkownika lub domyślny? Czy ma jakieś prywatne atrybuty członka? Inicjalizacja w C++ nie jest prosta. –
Całkiem zabawne, że @xtofl prosi plakat o usunięcie "Jestem zaznajomiony z C++" ... Może większość ludzi nie jest tak "zaznajomiona" z C++, gdy prawie wszystkie odpowiedzi są błędne. W rzeczywistości inicjowanie jest trudne, niektóre osoby, które udzieliły odpowiedzi, udowodniły swoją znajomość C++ @JaredPar, @dirkgently, @David Thornley, a mimo to nie udało się. –