Aracılığıyla paylaş


Oluşturucular (C++)

Bir sınıfın üyelerini başlatma biçimini özelleştirmek veya sınıfınızın bir nesnesi oluşturulduğunda işlevleri çağırmak için bir oluşturucu tanımlayın. Oluşturucu sınıfla aynı ada sahiptir ve dönüş değeri yoktur. Başlatmayı çeşitli yollarla özelleştirmek için gerektiği kadar aşırı yüklenmiş oluşturucu tanımlayabilirsiniz. Genellikle, sınıf tanımı veya devralma hiyerarşisi dışındaki kodun sınıfın nesnelerini oluşturabilmesi için oluşturucuların genel erişilebilirliği vardır. Ancak bir oluşturucuyu veya privateolarak protected da bildirebilirsiniz.

Oluşturucular isteğe bağlı olarak bir üye başlatıcı listesi alabilir. Bu, oluşturucu gövdesinde değer atamaktan daha verimli bir şekilde sınıf üyelerini başlatır. Aşağıdaki örnekte üç aşırı yüklenmiş oluşturucuya sahip bir sınıf Box gösterilmektedir. Son iki kullanım üyesi başlatma listesi:

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

Bir sınıfın örneğini bildirdiğinizde, derleyici aşırı yükleme çözümleme kurallarına göre çağrılacak oluşturucuyu seçer:

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)
}
  • Oluşturucular , , explicitfriendveya constexprolarak inlinebildirilebilir.
  • Oluşturucu, volatile veya const volatileolarak constbildirilen bir nesneyi başlatabilir. Nesnesi oluşturucu tamamlandıktan sonra olur const .
  • Bir uygulama dosyasında oluşturucu tanımlamak için, buna diğer üye işlevleri gibi nitelenmiş bir ad verin: Box::Box(){...}.

Üye başlatıcı listeleri

Oluşturucu isteğe bağlı olarak, oluşturucu gövdesi çalışmadan önce sınıf üyelerini başlatan bir üye başlatıcı listesine sahip olabilir. (Üye başlatıcı listesi, türündeki başlatıcı listesiylestd::initializer_list<T>aynı şey değildir.)

Oluşturucunun gövdesinde değer atamak yerine üye başlatıcı listelerini tercih edin. Üye başlatıcı listesi üyeleri doğrudan başlatır. Aşağıdaki örnekte, iki nokta üst üste sonrasındaki identifier(argument) tüm ifadelerden oluşan üye başlatıcı listesi gösterilmektedir:

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

Tanımlayıcı bir sınıf üyesine başvurmalıdır; bağımsız değişkeninin değeriyle başlatılır. bağımsız değişkeni oluşturucu parametrelerinden biri, işlev çağrısı veya olabilir std::initializer_list<T>.

const üye ve başvuru türü üyeleri, üye başlatıcı listesinde başlatılmalıdır.

Türetilmiş oluşturucu çalıştırılmadan önce temel sınıfların tam olarak başlatıldığından emin olmak için başlatıcı listesindeki parametreli temel sınıf oluşturucularını çağırın.

Varsayılan oluşturucular

Varsayılan oluşturucuların genellikle parametresi yoktur, ancak varsayılan değerlere sahip parametreleri olabilir.

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

Varsayılan oluşturucular özel üye işlevlerinden biridir. Bir sınıfta oluşturucu bildirilmezse, derleyici örtük inline bir varsayılan oluşturucu sağlar.

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

Örtük bir varsayılan oluşturucuyu kullanırsanız, önceki örnekte gösterildiği gibi sınıf tanımında üyeleri başlatmayı unutmayın. Bu başlatıcılar olmadan üyeler başlatılmaz ve Volume() çağrısı bir çöp değeri üretir. Genel olarak, örtük bir varsayılan oluşturucuya bağlı olmasa bile üyeleri bu şekilde başlatmak iyi bir uygulamadır.

Derleyiciyi silinmiş olarak tanımlayarak örtük bir varsayılan oluşturucu oluşturmasını engelleyebilirsiniz:

    // Default constructor
    Box() = delete;

Herhangi bir sınıf üyesi varsayılan olarak oluşturulamazsa, derleyici tarafından oluşturulan varsayılan oluşturucu silinmiş olarak tanımlanır. Örneğin, sınıf türünün tüm üyeleri ve sınıf türü üyeleri, erişilebilir bir varsayılan oluşturucuya ve yıkıcıya sahip olmalıdır. Başvuru türü ve tüm üyelerin tüm const veri üyeleri varsayılan üye başlatıcıya sahip olmalıdır.

Derleyici tarafından oluşturulan bir varsayılan oluşturucuyu çağırıp parantez kullanmayı denediğinizde, bir uyarı verilir:

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

Bu deyim , "En Çok Vexing Ayrıştırma" sorununa bir örnektir. İşlev bildirimi olarak veya varsayılan oluşturucunun çağrılması olarak yorumlayabilirsiniz myclass md(); . C++ ayrıştırıcıları bildirimleri diğer şeylere tercih ettiğinden, ifade işlev bildirimi olarak değerlendirilir. Daha fazla bilgi için bkz . En Çok Vexing Ayrıştırma.

Varsayılan olmayan oluşturucular bildirilirse, derleyici varsayılan bir oluşturucu sağlamaz:

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
}

Bir sınıfın varsayılan oluşturucusunun olmaması durumunda, bu sınıfın nesneleri dizisi tek başına köşeli ayraç söz dizimi kullanılarak oluşturulamaz. Örneğin, önceki kod bloğu göz önüne alındığında, bir Kutu dizisi şu şekilde bildirilemiyor:

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

Ancak, Box nesneleri dizisini başlatmak için bir başlatıcı listeleri kümesi kullanabilirsiniz:

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

Daha fazla bilgi için bkz . Başlatıcılar.

Oluşturucuları kopyalama

Kopyalama oluşturucu, üye değerlerini aynı türdeki bir nesneden kopyalayarak bir nesneyi başlatır. Sınıf üyelerinizin tümü skaler değerler gibi basit türlerse, derleyici tarafından oluşturulan kopya oluşturucu yeterlidir ve kendi kopyanızı tanımlamanız gerekmez. Sınıfınız daha karmaşık bir başlatma gerektiriyorsa, özel bir kopya oluşturucu uygulamanız gerekir. Örneğin, bir sınıf üyesi bir işaretçiyse, yeni bellek ayırmak ve değerleri diğerinin işaret edilen nesnesinden kopyalamak için bir kopya oluşturucu tanımlamanız gerekir. Derleyici tarafından oluşturulan kopya oluşturucu, işaretçiyi kopyalayarak yeni işaretçinin diğerinin bellek konumunu işaret edebilmesini sağlar.

Kopya oluşturucu şu imzalardan birine sahip olabilir:

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

Bir kopya oluşturucu tanımlarken, bir kopyalama atama işleci de (=) tanımlamanız gerekir. Daha fazla bilgi için bkz . Atama ve Kopyalama oluşturucuları ve kopyalama atama işleçleri.

Kopya oluşturucuyu silinmiş olarak tanımlayarak nesnenizin kopyalanmasını engelleyebilirsiniz:

    Box (const Box& other) = delete;

Nesneyi kopyalamaya çalışılması C2280: silinen bir işleve başvurmaya çalışırken hata oluşturur.

Oluşturucuları taşıma

Taşıma oluşturucu, var olan bir nesnenin verilerinin sahipliğini özgün verileri kopyalamadan yeni bir değişkene taşıyan özel bir üye işlevidir. İlk parametresi olarak bir rvalue başvurusu alır ve sonraki parametrelerin varsayılan değerleri olmalıdır. Taşıma oluşturucuları, büyük nesneleri geçirirken programınızın verimliliğini önemli ölçüde artırabilir.

Box(Box&& other);

Derleyici, nesne aynı türdeki başka bir nesne tarafından başlatıldığında, diğer nesne yok edilmek üzereyse ve artık kaynaklarına ihtiyaç duyuyorsa bir taşıma oluşturucu seçer. Aşağıdaki örnekte, bir taşıma oluşturucunun aşırı yükleme çözümlemesi ile seçilmesine neden olan bir durum gösterilmektedir. çağıran get_Box()oluşturucuda, döndürülen değer bir xvalue (eXpiring değeri) değeridir. Herhangi bir değişkene atanmadığından kapsamın dışına çıkmak üzeredir. Bu örnekte motivasyon sağlamak için Box'a içeriğini temsil eden büyük bir dize vektörünü verelim. Taşıma oluşturucu, vektör ve dizelerini kopyalamak yerine, "box" süresi dolan değerden "çalar", böylece vektör artık yeni nesneye ait olur. hem std::move hem de vectorstring sınıflar kendi taşıma oluşturucularını uyguladığından çağrısı yeterlidir.

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

Bir sınıf taşıma oluşturucu tanımlamazsa, kullanıcı tarafından bildirilen kopya oluşturucu, kopyalama atama işleci, taşıma atama işleci veya yok edici yoksa, derleyici örtük bir oluşturucu oluşturur. Açık veya örtük taşıma oluşturucu tanımlanmamışsa, taşıma oluşturucu kullanan işlemler bunun yerine kopya oluşturucuyu kullanır. Bir sınıf bir taşıma oluşturucu veya taşıma atama işleci bildirirse, örtük olarak bildirilen kopya oluşturucu silinmiş olarak tanımlanır.

Örtük olarak bildirilen taşıma oluşturucu, sınıf türü olan üyelerin yok edicisi yoksa veya derleyici taşıma işlemi için hangi oluşturucunun kullanılacağını belirleyemiyorsa silinmiş olarak tanımlanır.

Önemsiz olmayan bir taşıma oluşturucu yazma hakkında daha fazla bilgi için bkz . Oluşturucuları Taşıma ve Atama İşleçlerini Taşıma (C++).

Açıkça varsayılan ve silinmiş oluşturucular

Açıkça varsayılan kopya oluşturucuları, varsayılan oluşturucuları, taşıyıcıları taşıyabilir, atama işleçlerini kopyalayabilir, atama işleçlerini ve yıkıcıları taşıyabilirsiniz. Tüm özel üye işlevlerini açıkça silebilirsiniz .

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

Daha fazla bilgi için bkz . Açıkça Varsayılan Ve Silinmiş İşlevler.

constexpr oluşturucuları

Bir oluşturucu constexpr olarak bildirilebilir

  • varsayılan olarak bildirilir veya genel olarak constexpr işlevleri için tüm koşulları karşılar;
  • sınıfının sanal temel sınıfı yoktur;
  • parametrelerin her biri değişmez değer türündedir;
  • gövde bir işlev try-block değildir;
  • tüm statik olmayan veri üyeleri ve temel sınıf alt nesneleri başlatılır;
  • sınıfı (a) değişken üyeleri olan bir birleşimse veya (b) anonim birleşimlere sahipse, birleşim üyelerinden yalnızca biri başlatılır;
  • sınıf türünün statik olmayan her veri üyesi ve tüm temel sınıf alt nesnelerinde bir constexpr oluşturucu vardır

Başlatıcı listesi oluşturucuları

Bir oluşturucu parametresi olarak bir std::initializer_list<T> alırsa ve diğer parametrelerin varsayılan bağımsız değişkenleri varsa, sınıf doğrudan başlatma yoluyla örneklendiğinde bu oluşturucu aşırı yükleme çözümlemesinde seçilir. kabul eden herhangi bir üyeyi başlatmak için initializer_list kullanabilirsiniz. Örneğin, Box sınıfının (daha önce gösterilen) bir std::vector<string> üyesi m_contentsolduğunu varsayalım. Aşağıdakine benzer bir oluşturucu sağlayabilirsiniz:

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

Ardından aşağıdaki gibi Box nesneleri oluşturun:

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

Açık oluşturucular

Bir sınıfın tek bir parametresi olan bir oluşturucu varsa veya biri dışındaki tüm parametreler varsayılan değere sahipse, parametre türü örtük olarak sınıf türüne dönüştürülebilir. Örneğin, sınıfın Box aşağıdaki gibi bir oluşturucu varsa:

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

Aşağıdaki gibi bir Kutu başlatmak mümkündür:

Box b = 42;

Veya bir int'i Box alan bir işleve geçirin:

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

Bu tür dönüştürmeler bazı durumlarda yararlı olabilir, ancak daha sık kodunuzda küçük ama ciddi hatalara yol açabilir. Genel bir kural olarak, bu tür örtük tür dönüştürmesini önlemek için bir oluşturucuda (ve kullanıcı tanımlı işleçlerde) anahtar sözcüğünü kullanmanız explicit gerekir:

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

Oluşturucu açık olduğunda, bu satır derleyici hatasına neden olur: ShippingOrder so(42, 10.8);. Daha fazla bilgi için bkz . Kullanıcı Tanımlı Tür Dönüştürmeleri.

İnşaat sırası

Bir oluşturucu kendi işini şu sırayla gerçekleştirir:

  1. Temel sınıfı ve üye oluşturucuları bildirim sırasına göre çağırır.

  2. Sınıf sanal temel sınıflardan türetilmişse, nesnenin sanal taban işaretçilerini başlatır.

  3. Sınıf sanal işlevler içeriyorsa ya da devralıyorsa, nesnenin sanal işlev işaretçilerini başlatır. Sanal işlev işaretçileri, sanal işlev çağrılarının koda doğru bağlanmasını sağlamak için sınıfın sanal işlev tablosunu gösterir.

  4. Kendi işlev gövdesindeki tüm kodları yürütür.

Aşağıdaki örnek, türetilmiş bir sınıfın oluşturucusundaki temel sınıfın ve üye oluşturucuların çağrılma sırasını göstermektedir. İlk olarak, temel oluşturucu çağrılır. Ardından, temel sınıf üyeleri sınıf bildiriminde göründükleri sırayla başlatılır. Son olarak, türetilmiş oluşturucu çağrılır.

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

Çıkış şu şekildedir:

Contained1 ctor
Contained2 ctor
BaseContainer ctor
Contained3 ctor
DerivedContainer ctor

Bir türetilmiş sınıf oluşturucusu her zaman bir taban sınıf oluşturucusunu çağırır, böylece bu sınıf ek bir çalışma yapılmadan önce tümüyle oluşturulmuş taban sınıflarına dayanabilir. Temel sınıf oluşturucuları türetme sırasına göre çağrılır; örneğin, öğesinden ClassCClassCClassBtüretilmişseClassA, önce oluşturucu, sonra oluşturucu, sonra ClassBClassA oluşturucu çağrılır.

Bir temel sınıfın varsayılan oluşturucusunun olmaması durumunda, türetilmiş sınıf oluşturucusunda temel sınıf oluşturucu parametrelerini sağlamanız gerekir:

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

Bir oluşturucu özel bir durum oluşturursa, yok etme sırası oluşturma sırasının tersidir:

  1. Oluşturucu işlevinin gövdesindeki kod geriye doğru çözülür.

  2. Temel sınıf ve üye nesneleri bildirimin tersi sırada yok edilir.

  3. Oluşturucu temsilci seçmediyse, tamamen oluşturulmuş tüm temel sınıf nesneleri ve üyeleri yok edilir. Ancak, nesnenin kendisi tam olarak yapılandırılmadığından, yok edici çalıştırılamaz.

Türetilmiş oluşturucular ve genişletilmiş toplama başlatma

Bir temel sınıfın oluşturucusu genel değilse ancak türetilmiş bir sınıf için erişilebilirse, Visual Studio 2017 ve sonraki sürümlerde mod ve /std:c++17 sonraki sürümlerde türetilmiş türün nesnesini başlatmak için boş ayraç kullanamazsınız.

Aşağıdaki örnekte C++14 uyumlu davranışı gösterilmektedir:

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.

C++17'de artık Derived toplama türü olarak kabul edilir. Bu, özel varsayılan oluşturucu aracılığıyla başlatma Base işleminin, genişletilmiş toplama başlatma kuralının bir parçası olarak doğrudan gerçekleştiği anlamına gelir. Daha önce, Base özel oluşturucu oluşturucu aracılığıyla Derived çağrıldı ve bildirim nedeniyle friend başarılı oldu.

Aşağıdaki örnekte, Visual Studio 2017 ve sonraki sürümlerde moddaki /std:c++17 C++17 davranışı gösterilmektedir:

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'

Birden çok devralma içeren sınıflar için oluşturucular

Bir sınıf birden çok temel sınıftan türetilirse, temel sınıf oluşturucuları türetilen sınıfın bildiriminde listelendikleri sırayla çağrılır:

#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şağıdaki çıktıyı beklemelisiniz:

BaseClass1 ctor
BaseClass2 ctor
BaseClass3 ctor
DerivedClass ctor

Temsilci oluşturucuları

Temsilci seçme oluşturucu, başlatma işlerinin bir kısmını yapmak için aynı sınıftaki farklı bir oluşturucuyu çağırır. Bu özellik, tümünün benzer çalışmalar yapması gereken birden çok oluşturucunuz olduğunda kullanışlıdır. Ana mantığı bir oluşturucuya yazabilir ve başkalarından çağırabilirsiniz. Aşağıdaki önemsiz örnekte Box(int) çalışmasını Box(int,int,int) olarak temsil eder:

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

Herhangi bir oluşturucunun işi biter bitmez, oluşturucular tarafından oluşturulan nesne tamamen başlatılır. Daha fazla bilgi için bkz . Oluşturucuları Temsilci Olarak Belirleme.

Oluşturucuları devralma (C++11)

Türetilmiş bir sınıf, aşağıdaki örnekte gösterildiği gibi bir using bildirim kullanarak oluşturucuları doğrudan bir temel sınıftan devralabilir:

#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 ve üzeri: using Mod ve sonraki sürümlerdeki /std:c++17 deyimi, türetilmiş sınıftaki oluşturucularla aynı imzaya sahip olanlar dışında temel sınıftaki tüm oluşturucuları kapsama alır. Genel olarak, türetilen sınıf yeni veri üyesi veya oluşturucu bildirmediğinde devralan oluşturucuları kullanmak en iyisidir.

Bir sınıf şablonu, bu tür bir temel sınıf belirtiyorsa tür bağımsız değişkeninden tüm oluşturucuları devralabilir:

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

Bu temel sınıfların aynı imzaya sahip oluşturucuları varsa, türetici sınıf birden çok temel sınıftan devralamaz.

Oluşturucular ve bileşik sınıflar

Sınıf türü üyeleri içeren sınıflar bileşik sınıflar olarak bilinir. Bileşik bir sınıfın sınıf türünde bir üyesi oluşturulduğunda, sınıfın kendisi çağrılmadan önce oluşturucu çağrılır. İçerilen bir sınıfın varsayılan bir oluşturucusu yoksa, bileşik sınıfın oluşturucusunda bir başlatma listesi kullanmalısınız. Önceki StorageBox örnekte, üye değişkeninin m_label türünü yeni Label bir sınıfla değiştirirseniz, hem temel sınıf oluşturucuyu çağırmanız hem de oluşturucuda StorageBox değişkeni başlatmanız m_label gerekir:

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

Bu bölümde

Ayrıca bkz.

Sınıflar ve yapılar