2016-02-02 30 views
6

Questo programma di esempio mostra come verrà chiamato un costruttore diverso a seconda che si passi in una variabile locale, una variabile globale o una variabile anonima. Che cosa sta succedendo qui?C++ costruttore anonimo che fa cose strane

std::string globalStr; 
class aClass{ 
public: 
    aClass(std::string s){ 
    std::cout << "1-arg constructor" << std::endl; 
    } 
    aClass(){ 
    std::cout << "default constructor" << std::endl; 
    } 
    void puke(){ 
    std::cout << "puke" << std::endl; 
    } 
}; 

int main(int argc, char ** argv){ 
    std::string localStr; 
    //aClass(localStr); //this line does not compile 
    aClass(globalStr); //prints "default constructor" 
    aClass(""); //prints "1-arg constructor" 
    aClass(std::string("")); //also prints "1-arg constructor" 
    globalStr.puke(); //compiles, even though std::string cant puke. 
} 

Dato che posso chiamare globalStr.puke(), sto cercando di indovinare che chiamando aClass(globalStr);, si sta creando una variabile locale denominata globalStr di tipo aClass che viene utilizzato al posto del mondiale globalStr. Chiamando aClass(localStr); prova a fare la stessa cosa, ma non riesce a compilare perché localStr è già dichiarato come std::string. È possibile creare un'istanza anonima di una classe chiamando il suo costruttore 1-arg con un'espressione non costante? Chi ha deciso che type(variableName); dovrebbe essere un modo accettabile per definire una variabile denominata variableName?

+0

Che cos'è un _manonymous constructor_ ?? Non c'è nulla di cui io sia a conoscenza. –

+0

[Beh, è ​​interessante] (http://ideone.com/eNXYvI), perché può 'puke()' essere chiamato su una classe 'std :: string'. –

+1

@ πάνταῥεῖ, È ombreggiato dalla dichiarazione di 'globalStr' in' main'. – chris

risposta

12
aClass(localStr); //this line does not compile 

Questo tenta di dichiarare una variabile di tipo aClass nome localStr. La sintassi è terribile, sono d'accordo, ma ora è troppo tardi per [cambiare lo standard].

aClass(globalStr); //prints "default constructor" 

Questo dichiara uno chiamato globalStr. Questa variabile globalStr nasconde quella globale.

aClass(""); //prints "1-arg constructor" 

Questo crea un oggetto temporaneo di tipo aClass.

aClass(std::string("")); //also prints "1-arg constructor" 

Questo crea anche un temporaneo.

globalStr.puke(); //compiles, even though std::string cant puke. 

Questo utilizza il globalStr in main, che è coerente con ogni altra istanza di shadowing.

È possibile creare un'istanza anonima di una classe chiamando il suo costruttore 1-arg con un'espressione non costante?

Sì, mi viene in mente quattro modi:

aClass{localStr}; // C++11 list-initialization, often called "uniform initialization" 
(void)aClass(localStr); // The regular "discard this result" syntax from C. 
void(aClass(localStr)); // Another way of writing the second line with C++. 
(aClass(localStr)); // The parentheses prevent this from being a valid declaration. 

Come nota a margine, questa sintassi può essere spesso la causa del più fastidiosi Parse. Ad esempio, il seguente dichiara una funzione foo che restituisce aClass, con un parametro localStr di tipo std::string:

aClass foo(std::string(localStr)); 

In effetti è la stessa regola che è responsabile per i vostri problemi - Se qualcosa può essere analizzato come una dichiarazione valida, deve essere. Questo è il motivo per cui aClass(localStr); è una dichiarazione e non una dichiarazione costituita da un'espressione solitaria.