Perché il C ++ non ti permette di prendere l'indirizzo di un costruttore?

12

C'è una ragione specifica per cui questo potrebbe rompere la lingua concettualmente o un motivo specifico per cui questo è tecnicamente impossibile in alcuni casi?

L'utilizzo sarebbe con il nuovo operatore.

Modifica: ho intenzione di rinunciare alla speranza di ottenere il mio "nuovo operatore" e "operatore nuovo" direttamente ed essere diretto.

Il punto della domanda è: perché i costruttori sono speciali ? Tenete presente che le specifiche linguistiche ci dicono che cosa è legale, ma non necessariamente morale. Ciò che è legale è tipicamente informato da ciò che è logicamente coerente con il resto della lingua, ciò che è semplice e conciso e ciò che è fattibile per i compilatori da implementare. La possibile motivazione del comitato standard nel valutare questi fattori è deliberata e interessante - da qui la domanda.

    
posta Praxeolitic 20.06.2014 - 21:29
fonte

4 risposte

9

Le funzioni da puntatore a membro hanno senso solo se hai più di una funzione membro con la stessa firma, altrimenti ci sarebbe solo un possibile valore per il tuo puntatore. Ma ciò non è possibile per i contructor, poiché in C ++ diversi costruttori della stessa classe devono avere diverse firme.

L'alternativa a Stroustrup sarebbe stata quella di scegliere una sintassi per C ++ in cui i costruttori avrebbero potuto avere un nome diverso dal nome della classe - ma questo avrebbe impedito alcuni aspetti molto eleganti della sintassi del Ctor esistente e reso la lingua più complicata. Per me sembra un prezzo alto solo per consentire una funzionalità raramente necessaria che può essere simulata facilmente "esternalizzando" l'inizializzazione di un oggetto dal ctor a una diversa init function (una normale funzione membro per cui puntatore-a- i membri possono essere creati).

    
risposta data 20.06.2014 - 22:59
fonte
4

Un costruttore è una funzione che chiami quando l'oggetto non esiste ancora, quindi non può essere una funzione membro. Potrebbe essere statico.

Un costruttore viene effettivamente chiamato con questo puntatore, dopo che la memoria è stata allocata ma prima che sia stata completamente inizializzata. Di conseguenza, un costruttore ha un numero di funzioni privilegiate.

Se avessi un puntatore a un costruttore, dovrebbe essere un puntatore statico, qualcosa come una funzione di fabbrica o un puntatore speciale a qualcosa che verrebbe chiamato immediatamente dopo l'allocazione della memoria. Non può essere una funzione membro ordinaria e funziona ancora come costruttore.

L'unico scopo utile che viene in mente è un tipo speciale di puntatore che può essere passato al nuovo operatore per consentirgli di indirizzare su quale costruttore utilizzare. Immagino che potrebbe essere utile, ma richiederebbe una nuova sintassi significativa e presumibilmente la risposta è: ci hanno pensato e non ne è valsa la pena.

Se vuoi solo rifattorizzare il codice di inizializzazione comune, allora una normale funzione di memoria di solito è una risposta sufficiente, e puoi ottenere un puntatore a uno di questi.

    
risposta data 21.06.2014 - 09:45
fonte
-3

Questo perché il loro è un tipo di costruttore non restituito e non si riserva alcuno spazio per il costruttore in memoria. Come fai in caso di variabile durante la dichiarazione. Ad esempio: se scrivi una variabile semplice                           X Quindi il compilatore genererà un errore perché il compilatore non capirà il significato di questo. Ma quando scrivi                        Int x; Quindi il compilatore viene a sapere che int tipo di variabile dei dati, quindi riserverà un po 'di spazio per la variabile.

Conclusione: - quindi la conclusione è che a causa dell'esclusione del tipo di reso non verrà visualizzato l'indirizzo in memoria.

    
risposta data 10.10.2015 - 12:17
fonte
-4

Mi proverò a indovinare:

Costruttore e distruttore C ++ non sono affatto funzioni: sono macro. Vengono inclusi nello scope in cui viene creato l'oggetto e l'ambito in cui l'oggetto viene distrutto. A sua volta, non c'è costruttore né distruttore, l'oggetto è solo IS.

In realtà, penso che le altre funzioni della classe non siano funzioni nè funzioni inline che DONT si inline perché prendi il loro indirizzo (il compilatore si rende conto che ci sei dentro e non inline o inline il codice in la funzione e ottimizza tale funzione) e a sua volta la funzione sembra "essere ancora lì", anche se non lo farebbe se non avessi preso l'indirizzo.

La tabella virtuale dell'oggetto "C ++" non è come un oggetto JavaScript, dove puoi ottenere il suo costruttore e creare oggetti da esso in fase di esecuzione tramite new XMLHttpRequest.constructor , ma piuttosto una raccolta di puntatori a funzioni anonime che fungono da significa interfacciarsi con questo oggetto, escludendo la capacità di creare l'oggetto. E non ha nemmeno senso "cancellare" l'oggetto, perché è come cercare di eliminare una struttura, non è possibile: è solo un'etichetta dello stack, basta scriverla come preferisci sotto un'altra etichetta: sei libero di usa una classe come 4 numeri interi:

/* i imagine this string gets compiled into a struct, one of which's members happens to be a const char * which is initialized to exactly your string: no function calls are made during construction. */
std::string a = "hello, world";
int *myInt = (int *)(*((void **)&a));
myInt[0] = 3;
myInt[1] = 9;
myInt[2] = 20;
myInt[3] = 300;

Non c'è perdita di memoria, non ci sono problemi, tranne che hai sprecato in modo efficace un mucchio di spazio di stack che è riservato all'interfacciamento dell'oggetto e alla stringa, ma non distruggerà il tuo programma (finché non provi per usarlo come una stringa mai più).

In realtà, se le mie supposizioni precedenti sono corrette: il costo completo della stringa è solo il costo di memorizzare questi 32 byte e lo spazio costante della stringa: le funzioni vengono utilizzate solo in fase di compilazione e possono anche essere allineate e buttato via dopo che l'oggetto è stato creato e usato (come se si stesse lavorando con una struttura e ci si riferisse direttamente solo senza chiamate di funzione, ci sono sicuramente chiamate doppie anziché salti di funzione, ma di solito è più veloce e occupa meno spazio). In sostanza, ogni volta che chiami una funzione, il compilatore sostituisce semplicemente quella chiamata con le istruzioni per farlo letteralmente, con le eccezioni impostate dai progettisti di linguaggio.

Riepilogo: gli oggetti C ++ non hanno idea di cosa siano; tutti gli strumenti per l'interfacciamento con essi sono inline staticamente, e persi in fase di runtime. Ciò rende il lavoro con le classi efficiente come riempire le strutture con i dati e lavorare direttamente con quei dati senza chiamare alcuna funzione (queste funzioni sono in linea).

Questo è completamente diverso dagli approcci di COM / ObjectiveC e javascript, che mantengono le informazioni sul tipo in modo dinamico, a costo del sovraccarico di runtime, gestione della memoria, chiamate di costruzione, poiché il compilatore non può buttare via queste informazioni : è necessario per la spedizione dinamica. Questo a sua volta ci dà la possibilità di "Parlare" al nostro programma in fase di esecuzione, e di svilupparlo mentre è in esecuzione con componenti riflettenti.

    
risposta data 09.09.2016 - 00:52
fonte

Leggi altre domande sui tag