Historia pytania:
W klasycznym C++ członkowie klasy byli inicjalizowani tylko w liście inicjalizacji konstruktora. W C++11 pojawiła się możliwość podawania wartości domyślnych bezpośrednio w deklaracji wewnątrz klasy (inicjalizatory członków) w celu poprawy czytelności i bezpieczeństwa kodu.
Problem:
Istnieje kilka sposobów przypisania wartości członkom klasy: bezpośrednio w deklaracji (in-class), przez listę inicjalizacji konstruktora i już w ciele konstruktora. Różne podejścia wpływają na wydajność i semantykę; niewłaściwe zrozumienie prowadzi do niepotrzebnego kopiowania lub domyślnych destruktorów, błędów związanych z stałymi i referencjami.
Rozwiązanie:
class MyClass { int x = 42; };
class MyClass { const int y; MyClass(int val) : y(val) {} // w przeciwnym razie — błąd kompilacji };
class MyClass { std::string s; MyClass() { s = "hello"; } // Najpierw default, potem przypisanie };
Kluczowe cechy:
Jaka będzie kolejność inicjalizacji członków: w kolejności, w jakiej są zadeklarowane w klasie, czy w kolejności z listy inicjalizacji?
Kolejność inicjalizacji zawsze jest taka, w jakiej członkowie są zadeklarowani w klasie, a nie w kolejności inicjalizacji z listy. Naruszenie tej kolejności jest niebezpieczne dla zależnych członków.
class A { int x = 1; int y = 2; A() : y(10), x(20) {} }; // x jest inicjalizowane przed y, mimo kolejności w liście
Czy można inicjalizować członka-stałą wewnątrz ciała konstruktora, jeśli nie został on zainicjowany w liście?
Nie. Stałe są inicjalizowane tylko w liście inicjalizacji. Przypisanie w ciele konstruktora — błąd kompilacji.
Co się stanie, jeśli przypiszemy wartość domyślną dla członka bezpośrednio w klasie przez in-class initializer i nadpiszemy ją w liście inicjalizacji konstruktora?
Zostanie użyta wartość z listy inicjalizacji konstruktora. Wartość domyślna jest używana tylko wtedy, gdy lista niczego nie wskazuje.
class C { int x = 10; C() : x(20) {} // x będzie równe 20 };
Klasa pracuje z plikiem. Plik zadeklarowany jako std::ofstream, a inicjalizowany w ciele konstruktora. Niebezpieczeństwo: przy konstruktorze domyślnym może być stworzony nieprawidłowy std::ofstream, co prowadzi do błędów w pracy z plikiem.
Zalety:
Wady:
Plik jest inicjalizowany w liście inicjalizacji, blokując błędne używanie pliku w stanie nieprawidłowym, a członkowie z danymi domyślnymi korzystają z in-class initializer.
Zalety:
Wady: