Megosztás a következőn keresztül:


Konstruktorok (C++)

Ha testre szeretné szabni, hogyan inicializálja az osztály a tagjait, vagy hogyan hívhatja meg a függvényeket az osztály egy objektumának létrehozásakor, definiáljon egy konstruktort. A konstruktor neve megegyezik az osztály nevével, és nincs visszatérési érték. Az inicializálás különböző módokon történő testreszabásához annyi túlterhelt konstruktort definiálhat, amennyi szükséges. A konstruktorok általában nyilvános akadálymentességgel rendelkeznek, így az osztálydefiníción vagy öröklési hierarchián kívüli kód létrehozhatja az osztály objektumait. De deklarálhat egy konstruktort protectedprivateis.

A konstruktorok tetszés szerint felvehetnek egy tag inicializáló listát. Hatékonyabb módszer az osztálytagok inicializálására, mint értékek hozzárendelése a konstruktor törzsében. Az alábbi példa egy három túlterhelt konstruktort tartalmazó osztályt Box mutat be. Az utolsó két használattag-init lista:

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

Osztálypéldány deklarálásakor a fordító kiválasztja, hogy melyik konstruktort hívja meg a túlterhelésfeloldás szabályai alapján:

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)
}
  • A konstruktorok deklarálhatók inline, explicitvagy friendconstexpr.
  • A konstruktor inicializálhat egy constvolatile , vagy const volatile. Az objektum a konstruktor befejeződése után válik const .
  • Ha konstruktort szeretne definiálni egy implementációs fájlban, adjon neki egy minősített nevet, mint bármely más tagfüggvény: Box::Box(){...}.

Tagi inicializáló listák

A konstruktorok opcionálisan rendelkezhetnek tag inicializáló listával, amely inicializálja az osztálytagokat a konstruktor törzsének futtatása előtt. (A tag-inicializálók listája nem ugyanaz, mint egy inicializáló.std::initializer_list<T>)

A tag inicializáló listák előnyben részesítése a konstruktor törzsében lévő értékek hozzárendelésével szemben. A tagok inicializálási listája közvetlenül inicializálja a tagokat. Az alábbi példában a tag inicializáló listája látható, amely a identifier(argument) kettőspont utáni összes kifejezésből áll:

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

Az azonosítónak egy osztálytagra kell hivatkoznia; inicializálva van az argumentum értékével. Az argumentum lehet az egyik konstruktorparaméter, egy függvényhívás vagy egy std::initializer_list<T>.

const a tagoknak és a referencia típusú tagoknak inicializálva kell lenniük a tagok inicializáló listájában.

Annak érdekében, hogy az alaposztályok teljesen inicializálva legyenek a származtatott konstruktor futtatása előtt, hívja meg a paraméteres alaposztály konstruktorokat az inicializálók listájában.

Alapértelmezett konstruktorok

Az alapértelmezett konstruktorok általában nem rendelkeznek paraméterekkel, de lehetnek alapértelmezett értékekkel rendelkező paraméterek.

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){}
...
}

Az alapértelmezett konstruktorok a speciális tagfüggvények egyike. Ha egy osztályban nincs konstruktor deklarálva, a fordító implicit inline alapértelmezett konstruktort biztosít.

#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
}

Ha implicit alapértelmezett konstruktorra támaszkodik, mindenképpen inicializálja a tagokat az osztálydefinícióban az előző példában látható módon. Az inicializálók nélkül a tagok nem lesznek inicializálva, és a Volume() hívás szemétértéket eredményezne. Általában célszerű ily módon inicializálni a tagokat, még akkor is, ha nem implicit alapértelmezett konstruktorra támaszkodik.

Megakadályozhatja, hogy a fordító implicit alapértelmezett konstruktort hozzon létre , ha töröltként definiálja:

    // Default constructor
    Box() = delete;

A fordító által létrehozott alapértelmezett konstruktor akkor lesz törölve, ha az osztálytagok nem alapértelmezetten konstruktorok. Az osztálytípus minden tagjának és osztálytípusának például elérhető alapértelmezett konstruktorsal és destruktorokkal kell rendelkeznie. Minden referencia típusú adattagnak és minden const tagnak rendelkeznie kell egy alapértelmezett tag inicializálóval.

Amikor meghív egy fordító által létrehozott alapértelmezett konstruktort, és zárójeleket próbál használni, figyelmeztetést ad ki:

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

Ez az állítás a "Legtöbb vexing parse" problémára mutat példát. Értelmezheti myclass md(); függvénydeklarációként vagy egy alapértelmezett konstruktor meghívásaként. Mivel a C++ elemzők más dolgokhoz képest előnyben részesítik a deklarációkat, a kifejezés függvénydeklarációként lesz kezelve. További információ: Most Vexing Parse.

Ha bármilyen nem alapértelmezett konstruktor deklarálva van, a fordító nem biztosít alapértelmezett konstruktort:

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
}

Ha egy osztálynak nincs alapértelmezett konstruktora, az osztály objektumtömbje nem hozható létre szögletes zárójeles szintaxissal. Az előző kódblokkot tekintve például a Dobozok tömbje nem deklarálható így:

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

Az inicializáló listákat azonban használhatja a Box-objektumok tömbjének inicializálásához:

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

További információ: Inicializálók.

Konstruktorok másolása

A másolási konstruktor inicializál egy objektumot úgy, hogy a tagértékeket egy azonos típusú objektumból másolja. Ha az osztálytagok olyan egyszerű típusok, mint a skaláris értékek, a fordító által létrehozott másolási konstruktor elegendő, és nem kell sajátot definiálnia. Ha az osztály összetettebb inicializálást igényel, akkor egyéni példánykonstruktort kell implementálnia. Ha például egy osztálytag mutató, akkor meg kell határoznia egy példánykonstruktort az új memória lefoglalásához és a másik irányított objektum értékeinek másolásához. A fordító által létrehozott másolási konstruktor egyszerűen átmásolja a mutatót, így az új mutató továbbra is a másik memóriahelyére mutat.

A példánykonstruktor az alábbi aláírások egyikével rendelkezhet:

    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");

Másoláskonstruktor definiálásakor a másolás-hozzárendelés operátorát (=) is meg kell határoznia. További információ: Hozzárendelési és másolási konstruktorok és másolási hozzárendelési operátorok.

A másolási konstruktor törlésként való definiálásával megakadályozhatja az objektum másolását:

    Box (const Box& other) = delete;

Az objektum másolásának megkísérlése C2280 hibát okoz: egy törölt függvényre próbál hivatkozni.

Konstruktorok áthelyezése

Az áthelyezési konstruktor egy speciális tagfüggvény, amely az eredeti adatok másolása nélkül áthelyezi egy meglévő objektum adatainak tulajdonjogát egy új változóba. Első paramétere egy rvalue-hivatkozás, a későbbi paramétereknek pedig alapértelmezett értékekkel kell rendelkezniük. A konstruktorok mozgatása jelentősen növelheti a program hatékonyságát, ha nagy objektumokon halad át.

Box(Box&& other);

A fordító egy áthelyezési konstruktort választ, amikor az objektumot egy másik, azonos típusú objektum inicializálja, ha a másik objektum hamarosan megsemmisül, és már nincs szüksége az erőforrásaira. Az alábbi példa egy esetet mutat be, amikor egy áthelyezési konstruktort túlterhelésfelbontás választ ki. A hívó get_Box()konstruktorban a visszaadott érték xvalue (eXpiring érték). Nincs hozzárendelve egyetlen változóhoz sem, ezért ki fog lépni a hatókörből. A példa motivációjának biztosításához adjunk a Boxnak egy nagy sztringvektort, amely a tartalmát képviseli. A vektor és a sztringek másolása helyett az áthelyezési konstruktor "ellopja" azt a lejáró "dobozból", hogy a vektor most az új objektumhoz tartozjon. A hívásra std::move csak azért van szükség, mert mind az string osztályok, mind vector az osztályok saját mozgató konstruktorokat implementálnak.

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

Ha egy osztály nem határoz meg áthelyezési konstruktort, a fordító implicit szerkezetet hoz létre, ha nincs felhasználó által deklarált másolási konstruktor, másolási hozzárendelés-operátor, áthelyezési hozzárendelési operátor vagy destruktor. Ha nincs definiálva explicit vagy implicit áthelyezési konstruktor, az áthelyezési konstruktort egyébként használó műveletek inkább a másolási konstruktort használják. Ha egy osztály áthelyezési konstruktort vagy áthelyezés-hozzárendelési operátort deklarál, az implicit módon deklarált példánykonstruktort a rendszer töröltként definiálja.

Az implicit módon deklarált áthelyezési konstruktor akkor lesz törölve, ha az osztálytípusú tagok nem rendelkeznek destruktorsal, vagy ha a fordító nem tudja meghatározni, hogy melyik konstruktort használja az áthelyezési művelethez.

A nem triviális áthelyezési konstruktorok írásáról további információt a Konstruktorok áthelyezése és a Hozzárendelési operátorok áthelyezése (C++) című témakörben talál.

Explicit módon alapértelmezett és törölt konstruktorok

Explicit módon alapértelmezett másolási konstruktorok, alapértelmezett konstruktorok, konstruktorok áthelyezése, hozzárendelési operátorok másolása, hozzárendelési operátorok áthelyezése és destruktorok áthelyezése. Az összes speciális tagfüggvényt explicit módon törölheti .

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;
    //...
};

További információ: Explicitly Defaulted and Deleted Functions.

constexpr konstruktorok

Konstruktor akkor deklarálható constexpr-ként , ha

  • vagy alapértelmezettként van deklarálva, vagy máskülönben megfelel a constexpr függvények általános feltételeinek;
  • az osztály nem rendelkezik virtuális alaposztályokkal;
  • az egyes paraméterek literál típusúak;
  • a test nem függvény-próbablokk;
  • a rendszer inicializálja az összes nem statikus adattagot és alaposztály-alobjektumot;
  • ha az osztály (a) egy olyan szakszervezet, amelynek tagjai variánsok, vagy b) névtelen szakszervezetekkel rendelkezik, a szakszervezeti tagok közül csak az egyik inicializálódik;
  • osztálytípus minden nem statikus adattagja és minden alaposztály-alobjektum rendelkezik constexpr konstruktorsal

Inicializáló lista konstruktorai

Ha egy konstruktor paraméterként használ egy std::initializer_list<T> konstruktort, és bármely más paraméter alapértelmezett argumentumokkal rendelkezik, akkor a konstruktor túlterhelési felbontásban lesz kiválasztva, amikor az osztályt közvetlen inicializálással példányosítjuk. A initializer_list használatával inicializálhatja az elfogadó tagokat. Tegyük fel például, hogy a Box osztálynak (korábban) van tagja std::vector<string>m_contents. Az alábbihoz hasonló konstruktort adhat meg:

    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)
{}

Ezután hozzon létre a Következőhöz hasonló Box-objektumokat:

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

Explicit konstruktorok

Ha egy osztálynak egyetlen paraméterrel rendelkező konstruktora van, vagy ha egy kivételével minden paraméter alapértelmezett értékkel rendelkezik, a paramétertípus implicit módon átalakítható az osztálytípusra. Ha például az Box osztálynak ilyen konstruktora van:

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

A következő módon inicializálhat egy dobozt:

Box b = 42;

Vagy adjon át egy intet egy olyan függvénynek, amely egy Dobozt vesz fel:

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);

Az ilyen átalakítások bizonyos esetekben hasznosak lehetnek, de gyakrabban apró, de súlyos hibákhoz vezethetnek a kódban. Általános szabályként a explicit kulcsszót egy konstruktoron (és felhasználó által definiált operátoron) kell használnia az implicit típuskonverzió megakadályozásához:

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

Ha a konstruktor explicit, ez a sor fordítási hibát okoz: ShippingOrder so(42, 10.8);. További információ: User-Defined Típuskonverziók.

Az építés rendje

A konstruktor a következő sorrendben végzi el a munkáját:

  1. Meghívja az alaposztályt és a tagkonstruktorokat a deklarálás sorrendjében.

  2. Ha az osztály virtuális alaposztályokból származik, inicializálja az objektum virtuális alapmutatóit.

  3. Ha az osztály rendelkezik vagy örökli a virtuális függvényeket, inicializálja az objektum virtuális függvénymutatóit. A virtuális függvénymutatók az osztály virtuális függvénytáblájára mutatnak, hogy lehetővé tegyék a virtuális függvényhívások kódhoz való helyes kötését.

  4. Végrehajtja a függvény törzsében található kódot.

Az alábbi példa azt mutatja be, hogy az alaposztály és a tagkonstruktorok milyen sorrendben vannak meghívva egy származtatott osztály konstruktorában. Először az alapkonstruktort nevezzük. Ezután a rendszer inicializálja az alaposztálytagokat abban a sorrendben, amelyben azok megjelennek az osztálydeklarációban. Végül a származtatott konstruktort nevezzük.

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

A kimenet a következő:

Contained1 ctor
Contained2 ctor
BaseContainer ctor
Contained3 ctor
DerivedContainer ctor

A származtatott osztálykonstruktorok mindig alaposztály-konstruktort hívnak, hogy a további munka előtt teljesen létrehozott alaposztályokra támaszkodjon. Az alaposztály konstruktorait származtatási sorrendben hívjuk meg – ClassA ha például abból származik ClassB, amelyből ClassCszármazik – a ClassC konstruktort nevezzük először, majd a ClassB konstruktort, majd a ClassA konstruktort.

Ha egy alaposztály nem rendelkezik alapértelmezett konstruktorsal, az alaposztály konstruktor paramétereit a származtatott osztálykonstruktorban kell megadnia:

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

Ha a konstruktor kivételt okoz, a megsemmisítés sorrendje az építés sorrendjének fordítottja:

  1. A konstruktorfüggvény törzsében lévő kód megkerülhetetlen.

  2. Az alaposztály- és tagobjektumok a deklaráció fordított sorrendjében megsemmisülnek.

  3. Ha a konstruktor nem delegálható, az összes teljesen összeállított alaposztály-objektum és tag megsemmisül. Mivel azonban maga az objektum nincs teljesen felépítve, a destruktor nem fut.

Származtatott konstruktorok és kiterjesztett aggregátum-inicializálás

Ha az alaposztály konstruktora nem nyilvános, de egy származtatott osztály számára elérhető, akkor nem használhat üres zárójeleket a származtatott típusú /std:c++17 objektumok inicializálásához a Visual Studio 2017-es és újabb verzióiban.

Az alábbi példa c++14 konform viselkedést mutat be:

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.

A C++17-ben Derived mostantól összesített típusnak számít. Ez azt jelenti, hogy a privát alapértelmezett konstruktoron keresztüli Base inicializálás közvetlenül történik a kiterjesztett összesítési inicializálási szabály részeként. Korábban a Base magánkonstruktort a Derived konstruktoron keresztül hívták meg, és a friend deklaráció miatt sikerült.

Az alábbi példa c++17 viselkedést mutat be a Visual Studio 2017-ben és újabb verzióiban /std:c++17 módban:

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'

Több öröklésű osztályok konstruktorai

Ha egy osztály több alaposztályból származik, a rendszer meghívja az alaposztály konstruktorait abban a sorrendben, amelyben a származtatott osztály deklarációjában szerepelnek:

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

A következő kimenetre kell számítania:

BaseClass1 ctor
BaseClass2 ctor
BaseClass3 ctor
DerivedClass ctor

Konstruktorok delegálása

A delegált konstruktor egy másik konstruktort hív meg ugyanabban az osztályban az inicializálási munka egy részének elvégzésére. Ez a funkció akkor hasznos, ha több konstruktorral rendelkezik, amelyeknek hasonló munkát kell elvégezniük. A fő logikát megírhatja egy konstruktorban, és meghívhatja másoktól. A következő triviális példában a Box(int) a munkáját a Box(int,int,int) számára delegálja:

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

A konstruktorok által létrehozott objektum teljes inicializálása azonnal befejeződik. További információ: Konstruktorok delegálása.

Konstruktorok öröklése (C++11)

A származtatott osztály a konstruktorokat egy közvetlen alaposztályból örökölheti egy using deklaráció használatával, ahogyan az a következő példában látható:

#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 és újabb verziók: A using módban és /std:c++17 később megjelenő utasítás hatókörbe helyezi az alaposztály összes konstruktorát, kivéve azokat, amelyek azonos aláírásúak a származtatott osztály konstruktoraival. Általában akkor érdemes öröklő konstruktorokat használni, ha a származtatott osztály nem deklarál új adattagokat vagy konstruktorokat.

Az osztálysablonok örökölhetik az összes konstruktort egy típusargumentumból, ha ez a típus alaposztályt határoz meg:

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

A származtatott osztályok nem örökölhetők több alaposztályból, ha az alaposztályok konstruktorai azonos aláírással rendelkeznek.

Konstruktorok és összetett osztályok

Az osztálytípusú tagokat tartalmazó osztályokat összetett osztályoknak nevezzük. Ha egy összetett osztály osztálytípusú tagja jön létre, a konstruktort az osztály saját konstruktora előtt hívják meg. Ha egy tartalmazott osztály nem rendelkezik alapértelmezett konstruktorsal, inicializálási listát kell használnia az összetett osztály konstruktorában. A korábbi StorageBox példában, ha a tagváltozó típusát egy új Label osztályra módosítja, az alaposztály konstruktorát m_label is meg kell hívnia, és inicializálnia kell a m_label változót a StorageBox konstruktorban:

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"});
}

Ebben a szakaszban

Lásd még

Osztályok és szerkezetek