2015-05-03 13 views
6

A ha una funzione statica A :: create() che crea un'istanza di A, esegue un'inizializzazione e restituisce un puntatore ad esso. Voglio creare una sottoclasse di A e hanno un simile create() func:cosa succede se lancio (un puntatore alla classe A) a (un puntatore alla sottoclasse B) in C++

class B : public A { 
public: 
    static B* create(); 
    int val; 
    //... 
} 

in questo B :: creare function() devo fare quanto segue:

B* B::create() { 
    auto b = (B*)A::create(); 
    b -> val = 0; 
    //... 
    return b; 
} 

È questo il modo giusto per farlo? Cosa succederà dopo il cast?

Follow-up: A ha un costruttore protetto/privato, Come dovrei scrivere B :: create() o il costruttore di B? Voglio che i vars ereditati da A abbiano gli stessi valori di quelli creati da A :: create() avrebbe

+6

Comportamento non definito. –

+0

Dipende da un sacco di cose se funzionerebbe; ma mai fare affidamento su un comportamento indefinito. – CoffeeandCode

+0

Evita i cast in stile C in C++ (usa invece 'dynamic_cast'). Inoltre, se le classi 'A' e' B' condividono dati simili, i membri considerano l'uso di mixin, composizione o ereditarietà per evitare la duplicazione del codice. – Dai

risposta

5

Il cast non farà nulla di ragionevole a meno che A::create() restituisca un puntatore a un oggetto B. Se A::create() restituisce un puntatore a un oggetto che non è un B hai un comportamento non definito.

In C++ si gestisce l'inizializzazione di oggetti mediante l'utilizzo di costruttori: l'inizializzazione delle classi di base viene ereditata e ciascuna derivata può eseguire qualsiasi inizializzazione personalizzata che deve eseguire. Il tuo B::create() sarebbe solo restituire un oggetto opportunamente costruito:

B::B() 
    : A() // initialize base 
    , val(0) { 
     // other initialization 
} 
B* B::create() { return new B(); } 
+0

Grazie mille! ma ora B :: create() non assegnerà valori alle variabili ereditate da A come A :: created(). Il mio follow-up sarebbe come utilizzare A :: create() in B :: create() o B :: B(), per inizializzare i campi ereditati – snickers2029

+1

Si dovrebbe correggere il costruttore 'A' in modo da inizializzare in' A :: create() 'non è necessario. Se hai bisogno di usare 'A :: create()' puoi usare 'A * aptr = A :: create(); * this = * aptr; 'nel costruttore di' B' (e ovviamente appropriatamente rilascia 'aptr'). Consiglio vivamente di non farlo e, invece, raccomando di riparare il costruttore di 'A'. –

2

Si potrebbe fare di classe B di un amico di un come questo

class A { 
public: 
    static A* createA(); 
    int varA; 

private: 
    friend class B; // Make B a friend so that B can use private constructor of A 

    A() 
    { 
     cout << "In A constructor" << endl; 

     varA = 5; // Initialize members of A here 
    } 
}; 

A* A::createA() 
{ 
    return new A; 
} 

class B : public A { 
public: 
    static B* createB(); 
    int varB; 
private: 
    B() 
    { 
     cout << "In B constructor" << endl; 

     varB = -5; // Initialize members of B here 
    } 
}; 

B* B::createB() 
{ 
    return new B; 
} 

int main() 
{ 
    cout << "Create A" << endl; 
    A* x=A::createA(); 
    cout << "x->varA is " << x->varA << endl; 
    cout << endl; 

    cout << "Create B" << endl; 
    B* y=B::createB(); 
    cout << "y->varA is " << y->varA << endl; 
    cout << "y->varB is " << y->varB << endl; 
    cout << endl; 

    delete x; 
    delete y; 
} 

Quando un nuovo B è fatta, il costruttore di un GET richiamato automaticamente e i membri di A saranno inizializzati.

uscita è:

Create A 
In A constructor 
x->varA is 5 

Create B 
In A constructor 
In B constructor 
y->varA is 5 
y->varB is -5 

Un altro modo è quello di rendere il costruttore di A protetta invece di privati.

Problemi correlati