2013-07-28 9 views
27

Ich versuche C++ nach einem Einführungskurs vor ein paar Jahren neu zu lernen und ich habe einige grundlegende Probleme. Mein aktuelles Problem tritt auf, wenn ich versuche, eine Friend-Funktion zu verwenden. Hier ist mein Code in 2 Dateien.Fehler mit mehreren Definitionen der Funktion

Erstens:

// fun.cpp 

#include <iostream> 
using namespace std; 

class classA { 
    friend void funct(); 
public: 
    classA(int a=1,int b=2):propa(a),propb(b){cout<<"constructor\n";} 
private: 
    int propa; 
    int propb; 
    void outfun(){ 
     cout<<"propa="<<propa<<endl<<"propb="<<propb<<endl; 
    } 
}; 
void funct(){      // ERROR HERE 
    cout<<"enter funct"<<endl; 
    classA tmp(1,2); 
    tmp.outfun(); 
    cout<<"exit funct"<<endl; 
} 

Zweitens:

// mainfile.cpp 
#include <iostream> 
#include "fun.cpp" 
using namespace std; 

int main(int nargin,char* varargin[]) { 
    cout<<"call funct"<<endl; 
    funct(); 
    cout<<"exit main"<<endl; 
    return 0; 
} 

Der Fehler, den ich bekommen habe ist, "multiple Definition von` Funkt() '". Verwende ich die falsche Syntax, wenn ich sie als Friend-Funktion deklariere?

Antwort

18

Das Problem ist, dass, wenn Sie fun.cpp an zwei Stellen in Ihrem Programm enthalten, Sie es am Ende zweimal definieren, was nicht gültig ist.

Sie möchten cpp Dateien nicht einschließen. Sie möchten Header-Dateien einschließen.

Die Header-Datei sollte nur die Klassendefinition haben. Die entsprechende cpp Datei, die Sie separat kompilieren, wird die Funktionsdefinition haben.

fun.hpp:

#include <iostream> 

class classA { 
    friend void funct(); 
public: 
    classA(int a=1,int b=2):propa(a),propb(b){std::cout<<"constructor\n";} 
private: 
    int propa; 
    int propb; 
    void outfun(){ 
     std::cout<<"propa="<<propa<<endl<<"propb="<<propb<< std::endl; 
    } 
}; 

fun.cpp:

#include "fun.hpp" 

using namespace std; 

void funct(){ 
    cout<<"enter funct"<<endl; 
    classA tmp(1,2); 
    tmp.outfun(); 
    cout<<"exit funct"<<endl; 
} 

mainfile.cpp:

#include <iostream> 
#include "fun.hpp" 
using namespace std; 

int main(int nargin,char* varargin[]) { 
    cout<<"call funct"<<endl; 
    funct(); 
    cout<<"exit main"<<endl; 
    return 0; 
} 

Beachten Sie, dass es in der Regel zu vermeiden using namespace std in Header-Dateien empfohlen.

+1

Auch kann es mit einigen Linkern helfen, Header Guard zu wickeln - Suche auf #ifndef –

+0

@CarlNorum Ich hatte den Eindruck, dass mehrere Definitionsfehler Linker Fehler nicht Kompilierung waren. Aber vielleicht irre ich mich. –

+2

Sie sind, aber Header-Wächter haben damit nichts zu tun. Nun, es sei denn, Sie machen etwas verrücktes in Ihren Kopfzeilen. –

37

Hier ist eine stark vereinfachte, aber hoffentlich relevante Ansicht dessen, was passiert, wenn Sie Ihren Code in C++ erstellen.

C++ die Last teilt der in den folgenden verschiedenen Phasen Maschine ausführbaren Code zu erzeugen -

  1. Preprocessing - Dies ist, wo alle Makros - #defines usw. Sie erweitert bekommen könnte werden.

  2. Kompilieren - Jede cpp-Datei zusammen mit allen #include d-Dateien in dieser Datei direkt oder indirekt (zusammen als Kompilierungseinheit bezeichnet) wird in maschinenlesbaren Objektcode konvertiert. Diese

    ist, wo C++ überprüft auch, dass alle Funktionen definiert (dh einen Körper in {} zB
    void Foo(int x){ return Boo(x); }) beziehen sich auf andere Funktionen in einer gültigen Weise enthält.

    Die Art und Weise, dass tut, ist durch das Beharren, dass Sie stellen Sie mindestens eine Deklaration dieser anderen Funktionen (zB void Boo(int);) vor dem Aufruf bereit, damit diese unter anderem überprüfen kann, ob Sie sie richtig aufrufen, entweder direkt in der cpp-Datei, in der sie aufgerufen wird, oder in der Regel in einem included Header-Datei

    Beachten Sie, dass nur t Der Maschinencode, der den Funktionen entspricht, die in diesem cpp definiert sind, und den eingeschlossenen Dateien wird als die Objektversion (Binärversion) dieser Kompilierungseinheit (z. Foo) und nicht die, die nur deklariert werden (z. B. Boo).

  3. Verlinkung - Dies ist die Phase, in der C++ in jeder Kompilierungseinheit nach deklarierten und aufgerufenen Komponenten sucht und diese mit den Stellen verknüpft, an denen sie aufgerufen wird. Wenn nun keine Definition dieser Funktion gefunden wurde, gibt der Linker auf und gibt Fehler aus. Ebenso, wenn es mehrere Definitionen der gleichen Funktion Signatur findet (im Wesentlichen den Namen und die Parametertypen nimmt es) es auch Fehler, wie sie es mehrdeutig betrachtet und will nicht ein willkürlich auszuwählen.

Letzteres ist, was in Ihrem Fall passiert. Indem Sie eine #include der fun.cpp Datei machen, haben sowohl fun.cpp als auch mainfile.cpp eine Definition von funct() und der Linker weiß nicht, welcher in Ihrem Programm zu verwenden ist und beschwert sich darüber.

Das Update als Vaughn oben erwähnt ist nicht mit der Definition von funct() in mainfile.cpp und stattdessen zu bewegen, um die Erklärung von funct() in einer separaten Header-Datei und schließt, dass in mainline.cpp die CPP-Datei aufzunehmen. Auf diese Weise wird der Compiler die Deklaration von funct() bekommen, mit zu arbeiten und der Linken würde nur eine Definition von funct() von fun.cpp bekommen und es mit dem Vertrauen wird.