Classi di base astratte e costruzione di copie, regole pratiche

8

Spesso è una buona idea avere una classe base astratta per isolare l'interfaccia dell'oggetto.

Il problema è che la costruzione di copie, IMHO, è praticamente interrotta di default in C ++, con i costruttori di copie generati di default.

Quindi, quali sono i trucchi quando hai una classe base astratta e puntatori raw nelle classi derivate?

class IAbstract
{
    ~IAbstract() = 0;
}

class Derived : public IAbstract
{
    char *theProblem;
    ...
}

IAbstract *a1 = new Derived();
IAbstract a2 = *a1;//???

E ora disattivi in modo pulito la costruzione della copia per l'intera gerarchia? Dichiara la costruzione della copia come privata in IAbstract ?

Esistono regole di tre con classi di base astratte?

    
posta Coder 11.03.2012 - 23:59
fonte

3 risposte

5

Copia la costruzione su una classe astratta dovrebbe essere resa privata nella maggior parte dei casi, così come l'operatore di assegnazione.

Le classi astratte sono, per definizione, fatte per essere un tipo polimorfico. Quindi non si conosce la quantità di memoria utilizzata dall'istanza e quindi non è possibile copiarla o assegnarla in modo sicuro. In pratica, rischi di affettare: link

Il tipo polimorfico, in C ++, non deve essere manipolato dal valore. Li manipoli per riferimento o per puntatore (o qualsiasi puntatore intelligente).

Questo è il motivo per cui Java ha reso l'oggetto manipolabile solo per riferimento e perché C # e D ha la separazione tra classi e strutture (la prima è di tipo polimorfico e di riferimento, la seconda è non polimorfica e il tipo di valore).

    
risposta data 12.03.2012 - 02:52
fonte
8

Potresti, ovviamente, renderlo protetto e vuoto, in modo che le classi derivate possano scegliere. Tuttavia, più in generale, il tuo codice è vietato comunque perché è impossibile istanziare IAbstract - perché ha una pura funzione virtuale. Di conseguenza, questo è generalmente un non-problema: le classi di interfaccia non possono essere istanziate e quindi non possono mai essere copiate e le tue classi derivate possono vietare o continuare a copiare come desiderano.

    
risposta data 12.03.2012 - 01:32
fonte
2

Rendendo privato il ctor e il compito (o dichiarandoli come = delete in C ++ 11) si disabilita la copia.

Il punto qui è dove devi farlo. Per rimanere con il tuo codice, IAbstract non è un problema. (nota che facendo ciò che hai fatto, assegni il *a1 IAbstract subobject a a2, perdendo qualsiasi riferimento a Derived . L'assegnazione del valore non è polimorfica)

Il problema arriva con Derived::theproblem . Copiare un derivato in un altro può infatti condividere i dati di *theproblem che potrebbero non essere progettati per essere condivisi (ci sono due istanze che possono chiamare delete theproblem nel loro distruttore).

In questo caso, è Derived che deve essere non copiabile e non assegnabile. Ovviamente, se rendi privata la copia in IAbstract , poiché la copia predefinita per Derived ne ha bisogno, Derived non sarà nemmeno copiabile. Ma se definisci il tuo Derived::Derived(const Derived&) senza chiamare IAbtract copy, puoi comunque copiarli.

Il problema è in Derivato e la soluzione deve rimanere in Derivato: se deve essere un oggetto solo dinamico accessibile solo da puntatori o riferimenti, è Derivato stesso che deve avere

class Derived
{
    ...
    Derived(const Derived&) = delete;
    Derived& operator=(const Derived&) = delete;
};

Fondamentalmente spetta al progettista della classe derivata (che dovrebbe sapere come funziona Derived e come viene gestito theproblem ) per decidere cosa fare con l'assegnazione e la copia.

    
risposta data 14.03.2012 - 13:26
fonte

Leggi altre domande sui tag