2017-10-15 3 views
3

wollte ich mit externer Verlinkung und unvollständigem Typ Erklärungen experimentieren und schrieb folgendes Beispiel:C++ extern Verknüpfung

Source.cpp:

//Source.cpp 
class A { 
public: 
    int a=10; 
}; 

A* var1 = new A(); 

void printA(A* arg) 
{ 
    cout << arg->a << endl; 
} 

source1.cpp:

//Source1.cpp 
class A 
{ 
public: 
    int b = 20; 
    int c = 30; 
}; 

A* var2 = new A(); 

void printB(A* a) 
{ 
    std::cout << a->b; 
} 

main. cpp:

//main.cpp 
class A; 
extern A* var1; 
extern A* var2; 
int main() 
{ 
    void printA(A*); 
    void printB(A*); 
    printA(var1); //Prints 10 
    printA(var2); //Prints 10 
    printB(var2); //Prints 10 
    return 0; 
} 

Nach dem ersten Anruf von printA() wird "10" wie erwartet gedruckt. Aber warum "10" wird auch nach dem zweiten Aufruf von printA() und printB() gedruckt?

Antwort

5

Willkommen in der wunderbaren Welt der One Definition Regelverletzungen. Sie haben zwei Klassen, die beide im Dateibereich definiert sind und einen Namen teilen.

Da Klassen standardmäßig eine externe Verknüpfung haben, haben Sie zwei Definitionen für dieselbe Klasse, die nicht miteinander übereinstimmen. Das macht dein Programm unpassend, der Compiler/Linker kann sich beschweren oder einfach nur komische Dinge tun.

Auf der anderen Seite, die Art und Weise interne Bindung für eine Klasse zu zwingen, ist es in einem ungenannten Namespace zu deklarieren:

namespace { 

    class A { 
    public: 
     int a=10; 
    }; 

} 

Da unbenannte Namensräume für jede Übersetzungseinheit eindeutig sind, werden Sie in der Tat haben zwei separate Klassendefinitionen. Der Vorbehalt besteht darin, dass Sie keine extern Variablen mehr von außerhalb der Übersetzungseinheit deklarieren können.

5

Ihr Programm verletzt die Eine-Definition-Regel in einer Weise, die keine Diagnose erfordert und daher schlecht ausgebildet ist. Zwei Übersetzungseinheiten in Ihrem Programm definieren beide eine Klasse mit der Bezeichnung A mit externer Verknüpfung, aber die Definitionen sind unterschiedlich. Der Compiler und der Linker dürfen annehmen, dass sie die gleiche Klasse sind. Es gibt keine "richtige" Ausgabe für Ihr Programm.

+0

Also das ist undefiniertes Verhalten? – Nikita

+0

@Nikita Der Standard sagt, dass es ein undefiniertes Verhalten ist, aber ich denke, sie wollten sagen, es ist schlecht geformt, keine Diagnose erforderlich. Wenn ein ungültiges NDR-Programm tatsächlich kompiliert und ausgeführt wird, ist das Verhalten nicht definiert. – Brian