2010-12-10 9 views
0

betrachten folgenden CodeFrage nach Wert von Klasse bekommen

#include <iostream> 
using namespace std; 
class MyClass{ 
    int a; 
    public: 
    MyClass(int j) {a = j;} 
    int geta(void) {return a;} 
}; 

int main(void) 
{ 
    MyClass ob = 99;    

    cout << ob.geta(); 
} 

Ausgabe dieses Codes ist 99 meine Frage ist folgende Aussage MyClass ob ist Objekt der Klasse MyClass erklären und ist eine solche Art von Erklärung erlaubt, die gleiche Objekt ist irgendeine Zahl? vielleicht konkretere Deklaration wäre MyClass ob (99) Was denkst du?

Antwort

2

Wenn Sie ein Objekt wie

MyClass ob =99 ; 

Sie erstellen grundsätzlich Konstruktor der Klasse aufrufen werden.

Gleiche gilt, wenn das Objekt als

MyClass ob(99); 

In diesem Fall auch genannt wird Konstruktor der Klasse erstellt wird.

+0

Nein, er ist nicht Copykonstruktor aufrufen. Fügen Sie 'MyClass (const MyClass & asdf) hinzu: a (asdf.a) {cout <<" cc call "<< endl;}' zu seinem Code. "cc call" wird nicht gedruckt. – x13n

+0

@ x13n Sie haben Recht, wenn mir das gefällt MyClass obj (99); Meine Klasse ob = obj; dann wird der Kopierkonstruktor – anand

+0

@ x13n heißen: Sie irren sich und das @ Alien01 war richtig an erster Stelle. Die Sprache gibt an, dass "MyClass ob = 99" äquivalent zu "MyClass ob (MyClass (99))" ist. Das heißt, der Compiler erstellt ein temporäres Konstrukt mit dem impliziten Konstruktor und * then * kopiert es dann in das reale Objekt. Der Effekt, den Sie sehen (fehlende Ausgabe von Ihrem Kopierkonstruktor), ist auf eine Optimierung zurückzuführen, bei der der Compiler das Temporäre an der gleichen Stelle wie das resultierende Objekt erstellen kann und somit die Kopie herausnimmt. Um dies zu überprüfen, deklarieren Sie den Kopierkonstruktor als privat und Sie erhalten einen Zugriffsfehler im Code. –

3

Sie haben einen Konstruktor zur Verfügung gestellt, der einen Int. Ohne explicit Schlüsselwort kann es implizit aufgerufen werden - wie hier. Wenn Sie MyClass ob(99) schreiben würden, würden Sie diesen Konstruktor explizit aufrufen. Es gibt keinen Unterschied, bis Sie den Konstruktor als explicit deklarieren. Sie würden einen Kompilierungsfehler erhalten, wenn Sie versuchen, einem Objekt mit explizitem Konstruktor ein int zuzuweisen.

BEARBEITEN: Ich überprüfte - es ist wirklich Kopierkonstruktor zu verwenden, wie David und Alien01 sagten. Es ist nur Visual Studio, das nicht dem Standard entspricht.

+0

Initialisierung wie 'MyClass ob = 99;' bedeutet, dass der Kopierkonstruktor verfügbar sein muss (z. B. Fehler, wenn es privat ist), aber das bedeutet nicht, dass der Kopierkonstruktor aufgerufen werden muss (kann weg optimiert werden). – visitor

2

Dies ist der interessante Teil:

MyClass(int j) {a = j;} 

standardmäßig ein Konstruktor mit einem einzigen Argument ist implizit, was bedeutet, dass der Compiler automatisch ruft es überall dort, wo Sie eine int zuweisen möchten, wo ein MyClass erwartet wird.

Wenn Sie dieses Verhalten nicht für Ihre Klasse wollen, einfach den Konstruktor

ändern
explicit MyClass(int j) {a = j;} 

Und das Verhalten ist weg, jetzt müssen Sie explizit (daher das Schlüsselwort) jedes Mal, wenn der Konstruktor aufrufen. Beachten Sie, dass das Schlüsselwort explicit nur in der Deklaration im Klassenhauptteil angezeigt werden sollte, nicht jedoch in einer Implementierung außerhalb des Hauptteils.

S.S .: Dies ist zum Beispiel, wie const char* automatisch eine std::string wird, wenn die letztere erwartet wird.

+1

+1 als die klarste Antwort bisher. Es sollte darauf hingewiesen werden, dass die meisten Konstruktoren mit einem einzelnen Argument explizit deklariert werden sollten, da eine implizite Konvertierung nur selten (wenn überhaupt) benötigt wird und beim Starten zu viel Ärger führen kann. –

1

Die allgemeine Antwort wurde bereits von anderen bereitgestellt, einschließlich @ x13n. Ich werde versuchen, etwas detaillierter zu erklären, was der Code wirklich bedeutet.

Die Syntax MyObject ob = anotherMyObject; entspricht MyObject obj(anotherMyObject);. Die Bedeutung ist Kopieren Sie das Konstrukt ob aus dem Objekt anotherMyObject. Der Compiler wird immer MyObject ob = ...; mit einem Aufruf des Kopierkonstruktors übereinstimmen (normalerweise MyObject(MyObject const &), kann aber auch MyObject(MyObject&) sein, wenn der Benutzer dies so erklärt).

In Ihrem speziellen Code ist die rechte Seite kein MyObject, daher kann es nicht als Argument an den Kopierkonstruktor übergeben werden und der Compiler wird versuchen, diese rhs in etwas umzuwandeln, das mit dem Kopierkonstruktor von verwendet werden kann MyObject Anwendung der allgemeinen Regeln. In Ihrem Fall ist es eine implizite Konstruktor, der ein int Argument, und das verwendet werden kann, eine temporäres MyObject zu erstellen, so dass der Compiler schreibt Ihren Code zu sein:

MyObject ob(MyObject(99)); 
//    ^^^ temporary created by the compiler to match the copy constructor 

Beachten Sie, dass dies nicht das gleiche ist wie MyObject ob(99), aber eine Kombination der int und kopieren Konstruktoren, auch wenn der Gesamteffekt ähnlich ist. Wenn der Konstruktor, der eine ganze Zahl annimmt, als explicit deklariert wurde, konnte der Compiler sie nicht zur Bereitstellung der Konvertierung verwenden, und der Code konnte nicht kompiliert werden.

In einem Kommentar zu einer anderen Antwort weist @x13n darauf hin, dass dies kein Aufruf des Kopierkonstruktors ist. Als ob Sie diesem Konstruktor eine Ablaufverfolgung hinzufügen würden, wird die Ablaufverfolgung nicht generiert. Das ist ein völlig anderes Problem, bei dem der Compiler die Kopie optimieren kann, indem er das temporäre in genau der gleichen Adresse erstellt, die ob nimmt. Dies kann auf zwei Arten verifiziert werden, wobei beide davon abhängig sind, dass der Compiler zwar die Kopie ausliefern kann, aber die gleichen Einschränkungen einhalten muss. So können wir MyObject ob(MyObject(99)) ungültig es zwei Möglichkeiten, entweder Zugriff auf den Copykonstruktor deaktivieren oder Deaktivieren der Aufruf an den Konstruktor mit einem temporären:

class test1 { 
    test1(test1 const &) {} // make the copy constructor private 
public: 
    test1(int) {} 
}; 
class test2 { 
public: 
    test2(test2 &) {} // make the copy constructor take a non-const reference 
         // i.e. disable the use of temporaries 
    test2(int) {} 
}; 
int main() { 
    test1 t1 = 99; // copy constructor is private in this context 
    test2 t2 = 99; // g++: no matching function call to test2::test2(test2) 
        // diagnostics will differ with other compilers 
}