Konstruktory (C++)

Chcete-li přizpůsobit, jak třída inicializuje své členy nebo vyvolat funkce při vytvoření objektu třídy, definujte konstruktor. Konstruktor má stejný název jako třída a žádná návratová hodnota. Můžete definovat tolik přetížených konstruktorů, kolik je potřeba k přizpůsobení inicializace různými způsoby. Konstruktory mají obvykle veřejnou přístupnost, aby kód mimo definici třídy nebo hierarchii dědičnosti mohl vytvářet objekty třídy. Můžete však také deklarovat konstruktor jako protected nebo private.

Konstruktory můžou volitelně převzít seznam inicializátorů členů. Je to efektivnější způsob, jak inicializovat členy třídy než přiřazování hodnot v těle konstruktoru. Následující příklad ukazuje třídu Box se třemi přetíženými konstruktory. Poslední dva seznamy inicializačních položek používají:

class Box {
public:
    // Default constructor
    Box() {}

    // Initialize a Box with equal dimensions (i.e. a cube)
    explicit Box(int i) : m_width(i), m_length(i), m_height(i) // member init list
    {}

    // Initialize a Box with custom dimensions
    Box(int width, int length, int height)
        : m_width(width), m_length(length), m_height(height)
    {}

    int Volume() { return m_width * m_length * m_height; }

private:
    // Will have value of 0 when default constructor is called.
    // If we didn't zero-init here, default constructor would
    // leave them uninitialized with garbage values.
    int m_width{ 0 };
    int m_length{ 0 };
    int m_height{ 0 };
};

Když deklarujete instanci třídy, kompilátor zvolí, který konstruktor se má vyvolat na základě pravidel přetížit rozlišení:

int main()
{
    Box b; // Calls Box()

    // Using uniform initialization (preferred):
    Box b2 {5}; // Calls Box(int)
    Box b3 {5, 8, 12}; // Calls Box(int, int, int)

    // Using function-style notation:
    Box b4(2, 4, 6); // Calls Box(int, int, int)
}
  • Konstruktory mohou být deklarovány jako inline, explicit, friendnebo constexpr.
  • Konstruktor může inicializovat objekt, který byl deklarován jako const, volatile nebo const volatile. Objekt se stane const po dokončení konstruktoru.
  • Chcete-li definovat konstruktor v implementačním souboru, dejte mu kvalifikovaný název jako jakákoli jiná členová funkce: Box::Box(){...}.

Seznamy inicializátorů členů

Konstruktor může volitelně mít seznam inicializátoru členů, který inicializuje členy třídy před spuštěním těla konstruktoru. (Seznam inicializátorů členů není totéž jako seznam inicializátorů typu std::initializer_list<T>.)

Upřednostňujte seznamy inicializátoru členů před přiřazováním hodnot v těle konstruktoru. Seznam inicializátoru člena přímo inicializuje členy. Následující příklad ukazuje seznam inicializátoru člena, který se skládá ze všech identifier(argument) výrazů za dvojtečku:

    Box(int width, int length, int height)
        : m_width(width), m_length(length), m_height(height)
    {}

Identifikátor musí odkazovat na člena třídy; inicializuje se hodnotou argumentu. Argumentem může být jeden z parametrů konstruktoru, volání funkce nebo std::initializer_list<T>.

const členy a členy referenčního typu musí být inicializovány v seznamu inicializátorů členů.

Chcete-li zajistit, aby základní třídy byly plně inicializovány před spuštěním odvozeného konstruktoru konstruktoru, zavolejte všechny parametrizované konstruktory základní třídy v seznamu inicializátoru.

Výchozí konstruktory

Výchozí konstruktory obvykle nemají žádné parametry, ale mohou mít parametry s výchozími hodnotami.

class Box {
public:
    Box() { /*perform any required default initialization steps*/}

    // All params have default values
    Box (int w = 1, int l = 1, int h = 1): m_width(w), m_height(h), m_length(l){}
...
}

Výchozí konstruktory jsou jednou ze speciálních členských funkcí. Pokud nejsou v třídě deklarovány žádné konstruktory, kompilátor poskytuje implicitní inline výchozí konstruktor.

#include <iostream>
using namespace std;

class Box {
public:
    int Volume() {return m_width * m_height * m_length;}
private:
    int m_width { 0 };
    int m_height { 0 };
    int m_length { 0 };
};

int main() {
    Box box1; // Invoke compiler-generated constructor
    cout << "box1.Volume: " << box1.Volume() << endl; // Outputs 0
}

Pokud spoléháte na implicitní výchozí konstruktor, nezapomeňte inicializovat členy v definici třídy, jak je znázorněno v předchozím příkladu. Bez těchto inicializátorů by členy byly neinicializovány a volání volume() by vytvořilo hodnotu uvolňování paměti. Obecně je vhodné inicializovat členy tímto způsobem, i když se nespoléhá na implicitní výchozí konstruktor.

Kompilátoru můžete zabránit v generování implicitního výchozího konstruktoru tak, že ho definujete jako odstraněný:

    // Default constructor
    Box() = delete;

Výchozí konstruktor vygenerovaný kompilátorem bude definován jako odstraněný, pokud nejsou členy třídy výchozí-konstruktible. Například všichni členové typu třídy a jejich členy typu třídy musí mít výchozí konstruktor a destruktory, které jsou přístupné. Všichni datové členy referenčního typu a všichni const členové musí mít výchozí inicializátor člena.

Když zavoláte výchozí konstruktor vygenerovaný kompilátorem a pokusíte se použít závorky, zobrazí se upozornění:

class myclass{};
int main(){
myclass mc();     // warning C4930: prototyped function not called (was a variable definition intended?)
}

Toto tvrzení je příkladem problému "Most Vexing Parse". Můžete interpretovat myclass md(); buď jako deklaraci funkce, nebo jako vyvolání výchozího konstruktoru. Vzhledem k tomu, že analyzátory C++ upřednostňují deklarace oproti jiným věcem, je výraz považován za deklaraci funkce. Další informace naleznete v tématu Většina vexing Parse.

Pokud jsou deklarovány nějaké jiné než výchozí konstruktory, kompilátor neposkytuje výchozí konstruktor:

class Box {
public:
    Box(int width, int length, int height)
        : m_width(width), m_length(length), m_height(height){}
private:
    int m_width;
    int m_length;
    int m_height;

};

int main(){

    Box box1(1, 2, 3);
    Box box2{ 2, 3, 4 };
    Box box3; // C2512: no appropriate default constructor available
}

Pokud třída nemá žádný výchozí konstruktor, pole objektů této třídy nelze vytvořit pomocí samotné syntaxe hranaté závorky. Například vzhledem k předchozímu bloku kódu nelze pole polí deklarovat takto:

Box boxes[3]; // C2512: no appropriate default constructor available

Sadu seznamů inicializátorů však můžete použít k inicializaci pole objektů Box:

Box boxes[3]{ { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };

Další informace naleznete v tématu Inicializátory.

Konstruktory kopírování

Konstruktor kopírování inicializuje objekt zkopírováním hodnot členů z objektu stejného typu. Pokud jsou členy třídy všechny jednoduché typy, jako jsou skalární hodnoty, je konstruktor kopírování vygenerovaný kompilátorem dostatečný a nemusíte definovat vlastní. Pokud vaše třída vyžaduje složitější inicializaci, musíte implementovat vlastní konstruktor kopírování. Pokud je například členem třídy ukazatel, musíte definovat konstruktor kopírování pro přidělení nové paměti a zkopírovat hodnoty z druhého objektu s odkazem na objekt. Konstruktor kopírování vygenerovaný kompilátorem jednoduše zkopíruje ukazatel, aby nový ukazatel stále odkazoval na umístění paměti druhého.

Konstruktor kopírování může mít jeden z těchto podpisů:

    Box(Box& other); // Avoid if possible--allows modification of other.
    Box(const Box& other);
    Box(volatile Box& other);
    Box(volatile const Box& other);

    // Additional parameters OK if they have default values
    Box(Box& other, int i = 42, string label = "Box");

Při definování konstruktoru kopírování byste také měli definovat operátor přiřazení kopírování (=). Další informace naleznete v tématu Přiřazení a kopírování konstruktory a operátory přiřazení kopírování.

Objektu můžete zabránit v kopírování definováním konstruktoru kopírování jako odstraněného:

    Box (const Box& other) = delete;

Při pokusu o zkopírování objektu dojde k chybě C2280: pokus o odkaz na odstraněnou funkci.

Konstruktory přesunutí

Konstruktor přesunutí je speciální členská funkce, která přesouvá vlastnictví dat existujícího objektu do nové proměnné bez kopírování původních dat. Jako první parametr přebírá odkaz rvalue a všechny pozdější parametry musí mít výchozí hodnoty. Konstruktory přesunutí můžou výrazně zvýšit efektivitu programu při předávání velkých objektů.

Box(Box&& other);

Kompilátor zvolí konstruktor přesunutí při inicializaci objektu jiným objektem stejného typu, pokud se druhý objekt chystá zničit a už nepotřebuje jeho prostředky. Následující příklad ukazuje jeden případ, kdy je konstruktor přesunutí vybrán přetížením rozlišení. V konstruktoru, který volá get_Box(), vrácená hodnota je xvalue (eXpiring hodnota). Nepřiřazuje se k žádné proměnné, a proto se chystá přejít mimo rozsah. Abychom pro tento příklad poskytli motivaci, dáme Boxu velký vektor řetězců, které představují jeho obsah. Místo kopírování vektoru a jeho řetězců ho konstruktor přesunu "ukradne" z hodnoty "box", takže vektor teď patří do nového objektu. std::move Volání je vše, co je potřeba, protože obě vector i string třídy implementují vlastní konstruktory přesunutí.

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

class Box {
public:
    Box() { std::cout << "default" << std::endl; }
    Box(int width, int height, int length)
       : m_width(width), m_height(height), m_length(length)
    {
        std::cout << "int,int,int" << std::endl;
    }
    Box(Box& other)
       : m_width(other.m_width), m_height(other.m_height), m_length(other.m_length)
    {
        std::cout << "copy" << std::endl;
    }
    Box(Box&& other) : m_width(other.m_width), m_height(other.m_height), m_length(other.m_length)
    {
        m_contents = std::move(other.m_contents);
        std::cout << "move" << std::endl;
    }
    int Volume() { return m_width * m_height * m_length; }
    void Add_Item(string item) { m_contents.push_back(item); }
    void Print_Contents()
    {
        for (const auto& item : m_contents)
        {
            cout << item << " ";
        }
    }
private:
    int m_width{ 0 };
    int m_height{ 0 };
    int m_length{ 0 };
    vector<string> m_contents;
};

Box get_Box()
{
    Box b(5, 10, 18); // "int,int,int"
    b.Add_Item("Toupee");
    b.Add_Item("Megaphone");
    b.Add_Item("Suit");

    return b;
}

int main()
{
    Box b; // "default"
    Box b1(b); // "copy"
    Box b2(get_Box()); // "move"
    cout << "b2 contents: ";
    b2.Print_Contents(); // Prove that we have all the values

    char ch;
    cin >> ch; // keep window open
    return 0;
}

Pokud třída nedefinuje konstruktor move, kompilátor vygeneruje implicitní konstruktor, pokud neexistuje žádný konstruktor kopírování deklarovaný uživatelem, operátor přiřazení kopírování, operátor přiřazení přesunutí nebo destruktor. Pokud není definován explicitní ani implicitní konstruktor přesunutí, operace, které by jinak používaly konstruktor move, místo toho konstruktor kopírování. Pokud třída deklaruje konstruktor přesunutí nebo operátor přiřazení přiřazení, implicitně deklarovaný konstruktor kopírování je definován jako odstraněný.

Implicitně deklarovaný konstruktor přesunutí je definován jako odstraněný, pokud některé členy, které jsou typy tříd, chybí destruktor nebo pokud kompilátor nemůže určit, který konstruktor se má použít pro operaci přesunutí.

Další informace o tom, jak napsat ne triviální konstruktor přesunutí, naleznete v tématu Přesunout konstruktory a operátory přiřazení přesunutí (C++).

Explicitně výchozí a odstraněné konstruktory

Můžete explicitně výchozí konstruktory kopírování, výchozí konstruktory, konstruktory přesunutí, operátory přiřazení kopírování, operátory přiřazení přesunutí a destruktory. Můžete explicitně odstranit všechny speciální členské funkce.

class Box2
{
public:
    Box2() = delete;
    Box2(const Box2& other) = default;
    Box2& operator=(const Box2& other) = default;
    Box2(Box2&& other) = default;
    Box2& operator=(Box2&& other) = default;
    //...
};

Další informace najdete v tématu Explicitně výchozí a odstraněné funkce.

constexpr – konstruktory

Konstruktor může být deklarován jako constexpr , pokud

  • je buď deklarován jako výchozí, nebo jinak splňuje všechny podmínky pro funkce constexpr obecně;
  • třída nemá žádné virtuální základní třídy;
  • každý z parametrů je literálový typ;
  • tělo není funkce try-block;
  • Všechny nestatické datové členy a podobjekty základní třídy jsou inicializovány;
  • pokud je třída (a) sjednocení, která má členy varianty, nebo (b) má anonymní sjednocení, inicializuje se pouze jeden z členů sjednocení;
  • každý nestatický datový člen typu třídy a všechny podobjekty základní třídy mají konstruktor constexpr.

Konstruktory seznamu inicializátorů

Pokud konstruktor přebírá std::initializer_list<T> jako jeho parametr a všechny ostatní parametry mají výchozí argumenty, tento konstruktor je vybrán v rozlišení přetížení při vytvoření instance třídy prostřednictvím přímé inicializace. Pomocí initializer_list můžete inicializovat libovolný člen, který ho může přijmout. Předpokládejme například, že třída Box (zobrazená dříve) má std::vector<string> člen m_contents. Můžete zadat konstruktor podobný tomuto:

    Box(initializer_list<string> list, int w = 0, int h = 0, int l = 0)
        : m_contents(list), m_width(w), m_height(h), m_length(l)
{}

A pak vytvořte objekty Boxu takto:

    Box b{ "apples", "oranges", "pears" }; // or ...
    Box b2(initializer_list<string> { "bread", "cheese", "wine" }, 2, 4, 6);

Explicitní konstruktory

Pokud má třída konstruktor s jedním parametrem nebo pokud všechny parametry kromě jednoho mají výchozí hodnotu, typ parametru lze implicitně převést na typ třídy. Pokud Box má například třída konstruktor podobný tomuto:

Box(int size): m_width(size), m_length(size), m_height(size){}

Pole je možné inicializovat takto:

Box b = 42;

Nebo předejte funkci int, která přebírá box:

class ShippingOrder
{
public:
    ShippingOrder(Box b, double postage) : m_box(b), m_postage(postage){}

private:
    Box m_box;
    double m_postage;
}
//elsewhere...
    ShippingOrder so(42, 10.8);

Tyto převody mohou být v některých případech užitečné, ale častěji můžou vést k drobným, ale vážným chybám v kódu. Obecně platí, že pro konstruktor (a uživatelem definované operátory) byste měli použít explicit klíčové slovo, abyste zabránili tomuto typu implicitního převodu typu:

explicit Box(int size): m_width(size), m_length(size), m_height(size){}

Pokud je konstruktor explicitní, tento řádek způsobí chybu kompilátoru: ShippingOrder so(42, 10.8);. Další informace naleznete v tématu Převody typů definované uživatelem.

Pořadí stavby

Konstruktor provádí svou práci v tomto pořadí:

  1. Volá základní třídu a členské konstruktory v pořadí deklarace.

  2. Pokud je třída odvozena z virtuálních základních tříd, inicializuje virtuální základní ukazatele na objekt.

  3. Pokud třída má nebo dědí virtuální funkce, inicializuje ukazatele virtuální funkce objektu. Virtuální funkce ukazatelů ukazuje na tabulku virtuální funkce třídy umožňující správnou vazbu volání virtuální funkce na kód.

  4. Je spuštěn libovolný kód v těle jeho funkce.

Následující příklad zobrazuje pořadí, ve kterém jsou volány základní třídy a konstruktory členů v konstruktoru pro odvozenou třídu. Nejprve se volá základní konstruktor. Potom jsou členy základní třídy inicializovány v pořadí, ve kterém se zobrazí v deklaraci třídy. Nakonec se volá odvozený konstruktor.

#include <iostream>

using namespace std;

class Contained1 {
public:
    Contained1() { cout << "Contained1 ctor\n"; }
};

class Contained2 {
public:
    Contained2() { cout << "Contained2 ctor\n"; }
};

class Contained3 {
public:
    Contained3() { cout << "Contained3 ctor\n"; }
};

class BaseContainer {
public:
    BaseContainer() { cout << "BaseContainer ctor\n"; }
private:
    Contained1 c1;
    Contained2 c2;
};

class DerivedContainer : public BaseContainer {
public:
    DerivedContainer() : BaseContainer() { cout << "DerivedContainer ctor\n"; }
private:
    Contained3 c3;
};

int main() {
    DerivedContainer dc;
}

Zde je výstup:

Contained1 ctor
Contained2 ctor
BaseContainer ctor
Contained3 ctor
DerivedContainer ctor

Konstruktor odvozené třídy vždy volá konstruktor základní třídy, aby se před provedením jakékoli další práce mohl spolehnout na zcela konstruované základní třídy. Konstruktory základní třídy jsou volána v pořadí odvození – například pokud ClassA je odvozena z , který je odvozen z ClassCClassB, ClassC konstruktor je volán jako první, pak ClassB konstruktor, pak konstruktor.ClassA

Pokud základní třída nemá výchozí konstruktor, je nutné zadat parametry konstruktoru základní třídy v konstruktoru odvozené třídy:

class Box {
public:
    Box(int width, int length, int height){
       m_width = width;
       m_length = length;
       m_height = height;
    }

private:
    int m_width;
    int m_length;
    int m_height;
};

class StorageBox : public Box {
public:
    StorageBox(int width, int length, int height, const string label&) : Box(width, length, height){
        m_label = label;
    }
private:
    string m_label;
};

int main(){

    const string aLabel = "aLabel";
    StorageBox sb(1, 2, 3, aLabel);
}

Pokud konstruktor vyvolá výjimku, pořadí zničení je obrácené pořadí konstrukce:

  1. Kód v těle funkce konstruktoru je oddělen.

  2. Základní třída a členské objekty jsou zničeny v obráceném pořadí deklarace.

  3. Pokud konstruktor není delegován, všechny plně vytvořené objekty a členy základní třídy jsou zničeny. Vzhledem k tomu, že samotný objekt není zcela sestavený, není destruktor spuštěný.

Odvozené konstruktory a rozšířená inicializace agregace

Pokud je konstruktor základní třídy neveřejný, ale přístupný pro odvozenou třídu, nemůžete použít prázdné složené závorky k inicializaci objektu odvozeného typu v /std:c++17 režimu a později v sadě Visual Studio 2017 a novější.

Následující příklad ukazuje chování odpovídající C++14:

struct Derived;

struct Base {
    friend struct Derived;
private:
    Base() {}
};

struct Derived : Base {};

Derived d1; // OK. No aggregate init involved.
Derived d2 {}; // OK in C++14: Calls Derived::Derived()
               // which can call Base ctor.

V jazyce C++17 Derived se nyní považuje za agregační typ. To znamená, že inicializace Base prostřednictvím privátního výchozího konstruktoru probíhá přímo v rámci rozšířeného pravidla inicializace agregace. Base Dříve byl privátní konstruktor volána prostřednictvím konstruktoru Derived a byl úspěšný z důvodu friend deklarace.

Následující příklad ukazuje chování jazyka C++17 v sadě Visual Studio 2017 a novějším v /std:c++17 režimu:

struct Derived;

struct Base {
    friend struct Derived;
private:
    Base() {}
};

struct Derived : Base {
    Derived() {} // add user-defined constructor
                 // to call with {} initialization
};

Derived d1; // OK. No aggregate init involved.

Derived d2 {}; // error C2248: 'Base::Base': can't access
               // private member declared in class 'Base'

Konstruktory pro třídy, které mají více dědičnosti

Pokud je třída odvozena z více základních tříd, konstruktory základní třídy jsou vyvolány v pořadí, ve kterém jsou uvedeny v deklaraci odvozené třídy:

#include <iostream>
using namespace std;

class BaseClass1 {
public:
    BaseClass1() { cout << "BaseClass1 ctor\n"; }
};
class BaseClass2 {
public:
    BaseClass2() { cout << "BaseClass2 ctor\n"; }
};
class BaseClass3 {
public:
    BaseClass3() { cout << "BaseClass3 ctor\n"; }
};
class DerivedClass : public BaseClass1,
                     public BaseClass2,
                     public BaseClass3
                     {
public:
    DerivedClass() { cout << "DerivedClass ctor\n"; }
};

int main() {
    DerivedClass dc;
}

Můžete očekávat následující výstup:

BaseClass1 ctor
BaseClass2 ctor
BaseClass3 ctor
DerivedClass ctor

Delegování konstruktorů

Delegující konstruktor volá jiný konstruktor ve stejné třídě, aby udělal některé práce inicializace. Tato funkce je užitečná, pokud máte více konstruktorů, které musí provádět podobnou práci. Hlavní logiku můžete napsat v jednom konstruktoru a vyvolat ji od ostatních. V následujícím triviálním příkladu box(int) deleguje svou práci na Box(int,int;int):

class Box {
public:
    // Default constructor
    Box() {}

    // Initialize a Box with equal dimensions (i.e. a cube)
    Box(int i) :  Box(i, i, i)  // delegating constructor
    {}

    // Initialize a Box with custom dimensions
    Box(int width, int length, int height)
        : m_width(width), m_length(length), m_height(height)
    {}
    //... rest of class as before
};

Objekt vytvořený pomocí konstruktorů je plně inicializován ihned po dokončení jakéhokoli konstruktoru. Další informace naleznete v tématu Delegování konstruktorů.

Dědění konstruktorů (C++11)

Odvozená třída může dědit konstruktory z přímé základní třídy pomocí using deklarace, jak je znázorněno v následujícím příkladu:

#include <iostream>
using namespace std;

class Base
{
public:
    Base() { cout << "Base()" << endl; }
    Base(const Base& other) { cout << "Base(Base&)" << endl; }
    explicit Base(int i) : num(i) { cout << "Base(int)" << endl; }
    explicit Base(char c) : letter(c) { cout << "Base(char)" << endl; }

private:
    int num;
    char letter;
};

class Derived : Base
{
public:
    // Inherit all constructors from Base
    using Base::Base;

private:
    // Can't initialize newMember from Base constructors.
    int newMember{ 0 };
};

int main()
{
    cout << "Derived d1(5) calls: ";
    Derived d1(5);
    cout << "Derived d1('c') calls: ";
    Derived d2('c');
    cout << "Derived d3 = d2 calls: " ;
    Derived d3 = d2;
    cout << "Derived d4 calls: ";
    Derived d4;
}

/* Output:
Derived d1(5) calls: Base(int)
Derived d1('c') calls: Base(char)
Derived d3 = d2 calls: Base(Base&)
Derived d4 calls: Base()*/

Visual Studio 2017 a novější: Příkaz using v /std:c++17 režimu a později přenese do oboru všechny konstruktory ze základní třídy s výjimkou těch, které mají stejný podpis jako konstruktory v odvozené třídě. Obecně je nejlepší použít dědění konstruktorů, když odvozená třída deklaruje žádné nové datové členy nebo konstruktory.

Šablona třídy může dědit všechny konstruktory z argumentu typu, pokud tento typ určuje základní třídu:

template< typename T >
class Derived : T {
    using T::T;   // declare the constructors from T
    // ...
};

Odvozená třída nemůže dědit z více základních tříd, pokud tyto základní třídy mají konstruktory, které mají identický podpis.

Konstruktory a složené třídy

Třídy, které obsahují členy typu třídy, se označují jako složené třídy. Při vytvoření člena typu třídy pro složenou třídu je konstruktor volán před vlastním konstruktorem třídy. Pokud obsažená třída nemá výchozí konstruktor, musíte použít seznam inicializace v konstruktoru složené třídy. Pokud v předchozím StorageBox příkladu změníte typ m_label členské proměnné na novou Label třídu, musíte volat konstruktor základní třídy a inicializovat m_label proměnnou v konstruktoru StorageBox :

class Label {
public:
    Label(const string& name, const string& address) { m_name = name; m_address = address; }
    string m_name;
    string m_address;
};

class StorageBox : public Box {
public:
    StorageBox(int width, int length, int height, Label label)
        : Box(width, length, height), m_label(label){}
private:
    Label m_label;
};

int main(){
// passing a named Label
    Label label1{ "some_name", "some_address" };
    StorageBox sb1(1, 2, 3, label1);

    // passing a temporary label
    StorageBox sb2(3, 4, 5, Label{ "another name", "another address" });

    // passing a temporary label as an initializer list
    StorageBox sb3(1, 2, 3, {"myname", "myaddress"});
}

V této části

Viz také

Třídy a struktury