2010-06-04 11 views
6

Questo è il codice:Qual è una possibile soluzione alternativa per l'affettamento degli oggetti in C++?

#include <string> 
#include <vector> 
#include <iostream> 
using namespace std; 
class A { 
public: 
    virtual const string f() const { return "A"; } 
}; 
class B : public A { 
public: 
    const string f() const { return "B"; } 
}; 
int main(int ac, char** av) { 
    vector<A> v; 
    v.push_back(B()); 
    cout << v.at(0).f() << endl; 
    return 0; 
} 

risultato atteso è B, ma è A. Come ho capito oggetto slicing è in corso. Come evitarlo? Devo memorizzare i puntatori in vector invece di istanze di oggetto? È questa l'unica scelta?

+0

L'affettamento degli oggetti, sebbene avvenga qui, non è ciò che causa il risultato errato, è l'invocazione della funzione dall'operatore membro (.) Le funzioni virtuali devono essere richiamate con l'operatore membro-puntatore (->) (eccetto quando si usano i riferimenti) – Ozan

+6

@Ozan: assurdità. Chiamare una funzione membro virtuale da un'altra funzione membro (virtuale o meno) comporterà anche una chiamata virtuale. – MSalters

+0

Sì, volevo solo sottolineare a Vincenzo che l'utilizzo dell'operatore membro, non l'affettamento degli oggetti, era il colpevole. È un errore comune quando le persone java/C# scrivono C++ – Ozan

risposta

11

È necessario memorizzare i puntatori. Se questi si riferiscono a oggetti allocati dinamicamente, utilizzare i puntatori intelligenti .

3

Bene, nel codice è possibile utilizzare un vettore di B. Si noti che le funzioni virtuali verranno inviate correttamente solo se chiamate tramite un puntatore o un riferimento. Tuttavia, supponendo che si desideri veramente che il vettore contenga sia gli oggetti A che B, è necessario renderlo vettoriale di puntatori A e creare dinamicamente gli oggetti A e B.

11

Ordinato dal più semplice, al più complesso (ma più bello).

Soluzione 1:

vector<B> v; 
v.push_back(B()); 
cout << v.at(0).f() << endl; 

Soluzione 2:

vector<A*> v; 
v.push_back(new B()); 
cout << v.at(0)->f() << endl; 
while(!v.empty()) { delete v.back(); v.pop_back(); } 

Soluzione 3:

vector<boost::shared_ptr<A>> v; 
v.push_back(boost::make_shared<B>()); 
cout << v.at(0)->f() << endl; 

Se non w Affinché ciò accada, è necessario tenere in considerazione il fatto che oggetti diversi possono avere dimensioni diverse - quindi è necessaria una soluzione che possa funzionare con dimensioni variabili - il che rende l'archiviazione in heap un must.

+2

' vector > v; 'è una pessima idea. Mai memorizzare 'auto_ptr' in un vettore, dato che il suo codice di copia modifica l'oggetto passato. Vedere questo: http: //www.gotw.ca/publications/using_auto_ptr_effectively.htm per il motivo. – Naveen

+0

@Naveen, lo so, eppure è l'unico puntatore intelligente pre-TR1. –

+0

Sono sicuro che in realtà è _forbidden_ ​​per farlo. 'std :: auto_ptr' non soddisfa i requisiti per un elemento contenitore. – sbi

Problemi correlati