Türetilmiş sınıf oluşturucusunda temel sınıf üye değişkenlerini nasıl başlatabilirim?


123

Bunu neden yapamıyorum?

class A
{
public:
    int a, b;
};

class B : public A
{
    B() : A(), a(0), b(0)
    {
    }

};

7
Bunu neden yapamayacağınızı mı soruyorsunuz , bu bir dil tasarımı sorusudur, yoksa bu dil sınırlamasına nasıl çözüm bulunacağını mı soruyorsunuz ?
Rob Kennedy

Temel kurucuyu kullanmak zorunda kalmadan bunu yapmanın farkında olmadığım özel bir yolu olduğunu düşündüm.
amrhassan

Temel sınıf üyeleri, türetilmiş sınıf oluşturucunuzun çalışmaya başlamasıyla zaten başlatılmıştır. Sen edebilirsiniz atamak sen erişiminiz varsa, bunları, ya da onlar için ayarlayıcılar arayın veya uygun bir tane varsa sen, temel sınıf yapıcısı onlar için değerleri sağlayabilmektedir. Eğer bir şey olamaz icat sınıfta yapmak ilklendir onlar.
Marquis of Lorne

Yanıtlar:


143

Sen başlatılamıyor ave biçinde Bonlar üyesi olmayan çünkü B. Üyesidirler A, bu nedenle yalnızca Aonları başlatabilirler. Bunları herkese açık hale getirebilir, sonra içinde atama yapabilirsiniz B, ancak bu, kapsüllemeyi yok edeceği için önerilen bir seçenek değildir. Bunun yerine, onları başlatmaya (veya herhangi bir alt sınıfına ) Aizin vermek için bir yapıcı oluşturun :BA

class A 
{
protected:
    A(int a, int b) : a(a), b(b) {} // Accessible to derived classes
    // Change "protected" to "public" to allow others to instantiate A.
private:
    int a, b; // Keep these variables private in A
};

class B : public A 
{
public:
    B() : A(0, 0) // Calls A's constructor, initializing a and b in A to 0.
    {
    } 
};

32
Örneğiniz doğru iken, açıklamanız yanıltıcıdır. O değil olamaz işte başlatmak a ve bde B::B()onlar özeldir çünkü. Üyeleri olmadıkları için onları başlatamazsınız class B. Bunları halka açık hale getirdiyseniz veya koruyorsanız, bunları bünyesinde atayabilirsinizB::B() .
R Samuel Klatchko

2
ek olarak, çözümünüz A sınıfını toplu olmayan yapar, bu da önemli olabilir, bu nedenle belirtilmesi gerekir.
Gene Bushuyev

1
@R Samuel Klatchko: İyi nokta. Cevabı yazarken başlangıçta "Erişemezsin ave b..." yazdım ve cümlenin geri kalanının mantıklı olduğundan emin olmadan "İlklendiremezsin ..." olarak değiştirdim. Gönderi düzenlendi.
In silico

1
@Gene Bushuyev: Sorudaki orijinal koddaki sınıf bir toplu değil (statik olmayan özel üyeler var)
David Rodríguez - dribeas

@David - doğru, bu bir kullanıcının hatası ve yüzeysel olarak atlayarak kullanıcının niyetine ulaşmaya çalışıyorum.
Gene Bushuyev

26

Kenara bunlar aslında bırakılması privateiçin, ave bbir üyesi olan Abunlar tarafından başlatılması için amaçlanmıştır, Abireyin yapıcılar, başka bir sınıfın yapıcılar tarafından (türetilmiş ya da değil) olup.

Deneyin:

class A
{
    int a, b;

protected: // or public:
    A(int a, int b): a(a), b(b) {}
};

class B : public A
{
    B() : A(0, 0) {}
};

7

Her nasılsa, hiç kimse en basit yolu listelemedi:

class A
{
public:
    int a, b;
};

class B : public A
{
    B()
    {
        a = 0;
        b = 0;
    }

};

Başlatıcı listesindeki temel üyelere erişemezsiniz, ancak kurucunun kendisi, diğer herhangi bir üye yöntemi gibi, temel sınıfın publicve protectedüyelerine erişebilir .


1
Güzel. Bu şekilde yapmanın herhangi bir sakıncası var mı?
Wander3r

2
@SaileshD: Bir nesneyi pahalı bir kurucu ile başlatıyorsanız olabilir. Örneği Btahsis edildiğinde ilk önce varsayılan olarak başlatılacak , ardından B's yapıcısının içine atanacaktır . Ancak derleyicinin bunu hala optimize edebileceğini düşünüyorum.
Violet Giraffe

1
İçeride class Agüvenemeyiz ave bbaşlatılmayız. class C : public AÖrneğin herhangi bir uygulama, aramayı unutabilir a=0;ve abaşlatılmamış bırakabilir .
Sparkofska

@Sparkofska, çok doğru. Alanları bildirirken yerinde ( class A { int a = 0;};) veya temel sınıfın yapıcısında varsayılan olarak başlatmak en iyisidir . Alt sınıflar, gerektiğinde bunları yapıcılarında yeniden başlatabilir.
Violet Zürafa

1
@ Wander3r Diğer bir dezavantaj, tüm sınıfların atama operatörlerine sahip olmamasıdır. Bazıları yalnızca inşa edilebilir, ancak atanamaz. O zaman bitirdiniz ...
Martin Pecka

2
# include<stdio.h>
# include<iostream>
# include<conio.h>

using namespace std;

class Base{
    public:
        Base(int i, float f, double d): i(i), f(f), d(d)
        {
        }
    virtual void Show()=0;
    protected:
        int i;
        float f;
        double d;
};


class Derived: public Base{
    public:
        Derived(int i, float f, double d): Base( i, f, d)
        {
        }
        void Show()
        {
            cout<< "int i = "<<i<<endl<<"float f = "<<f<<endl <<"double d = "<<d<<endl;
        }
};

int main(){
    Base * b = new Derived(10, 1.2, 3.89);
    b->Show();
    return 0;
}

Bu, Derived sınıf nesnesinde bulunan Base sınıf veri üyelerini başlatmak istemeniz, ancak bu değerleri Derived sınıf yapıcı çağrısı aracılığıyla arabirim oluşturmayı istemeniz durumunda çalışan bir örnektir.


1

Bu ender durumlarda yararlı olsa da (böyle olmasaydı, dil doğrudan buna izin verirdi), Üye deyiminden Base'e bir göz atın . Kodsuz bir çözüm değil, fazladan bir kalıtım katmanı eklemeniz gerekecek, ancak işi hallediyor. Ortak koddan kaçınmak için boost uygulamasını kullanabilirsiniz.


0

Neden yapamıyorsun Çünkü dil, türetilmiş sınıfın başlatıcı listesindeki temel sınıf üyelerini başlatmanıza izin vermez.

Bunu nasıl halledebilirsin? Bunun gibi:

class A
{
public:
    A(int a, int b) : a_(a), b_(b) {};
    int a_, b_;
};

class B : public A
{
public:
    B() : A(0,0) 
    {
    }
};

-1

Bir sınıf üyesi için görünürlük belirtmezseniz, varsayılan olarak "özel" olur. Üyelerinize bir alt sınıfta erişmek istiyorsanız özel veya korumalı yapmalısınız.


-1

Örneğinizdeki (*) A gibi toplama sınıfları, üyelerinin geneline sahip olmalı ve kullanıcı tanımlı oluşturucular içermemelidir. Başlatıcı listesiyle uyumlu hale getirilmiştir, örneğin A a {0,0};veya sizin durumunuzda B() : A({0,0}){}. Temel toplama sınıfının üyeleri, türetilmiş sınıfın yapıcısında tek tek başlatılamaz.

(*) Kesin olmak gerekirse, doğru bir şekilde belirtildiği gibi, özgün class Astatik olmayan üyeler nedeniyle orijinal bir toplu değildir

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.