Un "costruttore di oggetti" è un nome più breve per una "funzione con nome 'oggetto' che restituisce tipo 'oggetto'"?

8

Voglio dire, si tratta di scegliere le parole più che non c'è alcuna differenza tra la funzione e la chiamata del costruttore. La cosa chiamata "costruttore di un oggetto" può anche essere chiamata "funzione con nome object che restituisce tipo object ".

Si potrebbe sostenere che C ++ non consente di avere lo stesso nome di funzione e tipo; tuttavia, vi è una soluzione alternativa per farlo. Il C ++ ha uno speciale zucchero sintattico (che si chiama costruttore) con il quale è possibile creare una funzione con nome object restituendo il tipo object . Quindi penso che un costruttore possa essere visto e usato come una funzione indipendente.

Ci sono alcune importanti differenze semantiche che mi mancano qui?

    
posta user3123061 29.12.2016 - 00:26
fonte

4 risposte

16

Un costruttore è fondamentalmente un metodo, sì, ma è un metodo speciale.

Ad esempio, in C ++ un costruttore non è semplicemente una funzione che restituisce una nuova istanza di quel tipo. Se lo fosse, l'ereditarietà non funzionerebbe. Non è stato possibile chiamare i costruttori di base, perché avrebbero restituito anche una nuova istanza. Si finirebbe con una nuova istanza di A, che viene quindi restituita al costruttore di B che crea una nuova istanza di B, che viene quindi restituita al costruttore di C, ecc.

Invece un costruttore è più di un metodo di inizializzazione che viene chiamato automaticamente dall'host allocator. Quando, per esempio, chiami "nuovo" per creare un oggetto sull'heap, esso alloca la memoria per il tipo richiesto (utilizzando un allocatore di memoria, come malloc), quindi chiama il metodo di costruzione su di esso. Il compilatore ha regole speciali su come e in quale ordine, il costruttore può chiamare gli altri costruttori. Ad esempio, in C #, se non si richiama esplicitamente un costruttore di base, il compilatore aggiungerà una chiamata al costruttore predefinito di base.

Sono le regole su come il compilatore gestisce i costruttori che lo rendono diverso da "una funzione chiamata .ctor che restituisce un'istanza del tipo".

    
risposta data 29.12.2016 - 00:37
fonte
5

No, un costruttore di object è molto diverso da una funzione chiamata object e restituisce object . Un costruttore non ha un nome, ma è in gran parte un tecnicismo. Le differenze più importanti sono che un costruttore non ha un tipo di ritorno e che non può essere chiamato direttamente.

Un costruttore non restituisce nulla perché riceve un blocco di memoria e opera su quella memoria sul posto. Potrebbe essere utile se si dimentica il nome "costruttore" per un momento e si pensa come inizializzatore . Lo scopo del costruttore è non di costruire un oggetto "dal nulla". Il suo scopo è inizializzare un oggetto nel punto preciso in cui deve essere posizionato.

Se un costruttore doveva restituire un oggetto, quell'oggetto restituito (il valore restituito) avrebbe dovuto vivere da qualche parte (probabilmente nello stack), e lì, avrebbe dovuto essere inizializzato in qualche modo - stiamo andando a fare un giro qui.

Questo va di pari passo con il fatto che un costruttore non può mai essere chiamato direttamente. Se hai una classe object e utilizzi un'espressione object() da qualche parte, non ha la semantica di "chiama il costruttore di object ". Ha la semantica di "creare un oggetto temporaneo di tipo object ". Il compilatore lo traduce nell'assegnare un posto dove il temporaneo possa vivere (probabilmente / comunemente nello stack), e chiama il costruttore per costruire (= inizializzare) un oggetto in quel luogo.

Lo stesso principio si applica quando si usa new object() . Questa è una nuova espressione, che fa due cose:

  1. Chiama una funzione di allocazione operator new (che restituisce un void* ) per allocare la memoria non elaborata per l'oggetto.
  2. Emettere una chiamata al costruttore su questa memoria non elaborata per costruire (= inizializzare) un oggetto in quel pezzo di memoria non elaborata.

Pensando a un costruttore di object come una funzione come questa:

static object object();

è sbagliato. Se mai, il modo in cui un costruttore lavora è più vicino a questo:

static void object(object &place_to_work_in);

Con l'eccezione che puoi mai chiamarlo direttamente. È sempre chiamato solo quando specificato da un costrutto di linguaggio diverso. Anche il posizionamento nuovo (noto anche come trucco "chiama un costruttore qui"), new (&place_for_object) object() , non chiama direttamente il costruttore. Si traduce in una chiamata al posizionamento, nuova forma di operator new che restituisce il suo argomento, seguito da una chiamata al costruttore (proprio come qualsiasi altra nuova espressione).

    
risposta data 29.12.2016 - 11:45
fonte
1

Il tuo tentativo di riformulazione non è corretto.

Sebbene un costruttore assomigli ad una funzione membro con un nome uguale al nome della classe, il fatto è che un costruttore non ha proprio un nome. Questo è esplicitamente dichiarato nello standard C ++ (sezione [class.ctor] / 1):

Constructors do not have names.

Per quanto riguarda: "Penso che un costruttore possa essere visto e usato come una funzione indipendente" va ... beh, non sono abbastanza sicuro di cosa intendi. Una funzione gratuita non può certamente essere un costruttore - un costruttore deve essere un membro di una classe. Allo stesso tempo, puoi certamente definire una funzione libera che crea un oggetto e restituisce un'istanza di quell'oggetto. Quella funzione libera può anche (sort) avere lo stesso nome del tipo di oggetto che crea, se si vuole abbastanza male. Ad esempio, puoi definire la classe all'interno di uno spazio dei nomi, quindi definire una funzione al di fuori dello spazio dei nomi:

namespace foo { 
    class bar {};
}

foo::bar bar() { return foo::bar(); }

Questo non è veramente lo stesso nome (la funzione è solo bar e la classe è foo::bar ), ma a seconda del tuo punto di vista, potresti guardarli in quel modo in ogni caso.

Tale funzione libera non avrebbe però le altre caratteristiche chiave di un costruttore. L'invocazione di un costruttore può essere completamente implicita. Ad esempio, se ho una classe come:

class foo {
public:
   foo (int) {}
   foo operator+(foo const &other) {}
};

... quindi codice come:

foo f(1);

foo h(0);
h = f + 1;

... può creare un oggetto temporaneo foo da 1 in modo che possa passare l'oggetto foo a foo::operator+ . Questo semplicemente non avverrà con una funzione libera, anche se quella funzione libera è stata definita per prendere il giusto tipo di parametro e restituire il tipo di risultato richiesto. Per tale conversione implicita, è richiesto un costruttore.

    
risposta data 29.12.2016 - 09:54
fonte
1

I mean, it's a matter of choosing words more than there is any difference between function and constructor call. The thing which is named "constructor of an object" can also be named "function with name object returning type object".

Per prima cosa, i costruttori non restituiscono nulla e, di conseguenza, non hanno tipi di ritorno.

In secondo luogo, i costruttori sono diversi in quanto non è possibile chiamare direttamente il costruttore direttamente nel modo in cui si chiamano le funzioni. Invece, se dichiari una variabile, i costruttori appropriati vengono richiamati dal runtime.

Terzo, in caso di ereditarietà, le funzioni regolari nelle sottoclassi sovrascrivono le funzioni nelle classi genitore. I costruttori, d'altro canto, vengono chiamati prima i costruttori di classi parent parent, quindi i costruttori di sottoclasse.

In quarto luogo, i costruttori possono avere elenchi di inizializzazione, mentre la funzione "normale" non può.

    
risposta data 29.12.2016 - 11:43
fonte

Leggi altre domande sui tag