web-dev-qa-db-fra.com

Erreur avec plusieurs définitions de fonction

J'essaie de réapprendre le C++ après avoir suivi un cours d'introduction il y a quelques années et j'ai quelques problèmes de base. Mon problème actuel survient lorsque j'essaie d'utiliser une fonction ami. Voici mon code en 2 fichiers.

Première:

// 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;
}

Seconde:

// 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;
}

L'erreur que j'obtiens est "définition multiple de` funct () '". Est-ce que j'utilise une mauvaise syntaxe lorsque je la déclare en tant que fonction amie?

43
Adad Dayos

Voici une vue très simplifiée mais, espérons-le, pertinente de ce qui se passe lorsque vous construisez votre code en C++.

C++ divise la charge de génération du code exécutable de la machine en différentes phases -

  1. prétraitement - C’est là que toutes les macros - #define, Etc. que vous pourriez utiliser sont éventuellement développées.

  2. Compilation - Chaque fichier cpp ainsi que tous les fichiers #include D de ce fichier, directement ou indirectement (ensemble appelée unité de compilation), sont convertis en code objet lisible par machine.

    C++ vérifie également que toutes les fonctions définies (c’est-à-dire contenant un corps dans {}, Par exemple void Foo( int x){ return Boo(x); }), font référence à d’autres fonctions de manière valide.

    Pour ce faire, vous devez insister pour que vous fournissiez au moins une déclaration de ces autres fonctions (par exemple, void Boo(int);) avant de l’appeler afin qu’il puisse vérifier que vous l’appeliez correctement, entre autres. Cela peut être fait directement dans le fichier cpp où il est appelé ou généralement dans un fichier d’en-tête inclus.

    Notez que seul le code machine correspondant aux fonctions définies dans ce fichier cpp et les fichiers inclus est construit en tant que version objet (binaire) de cette unité de compilation (par exemple, Foo), et pas ceux qui sont simplement déclarés (par exemple, Boo).

  3. Liaison - C’est l’étape où C++ recherche les éléments déclarés et appelés dans chaque unité de compilation et les relie aux lieux où ils sont appelés. Maintenant, si aucune définition de cette fonction n’a été trouvée, l’éditeur de liens cède et les erreurs s’échappent. De la même manière, s'il trouve plusieurs définitions de la même signature de fonction (essentiellement le nom et les types de paramètres qu'il prend), il se trompe également car il le considère comme ambigu et ne veut pas en choisir une de manière arbitraire.

Ce dernier est ce qui se passe dans votre cas. En faisant un #include Du fichier fun.cpp, fun.cpp Et mainfile.cpp Ont tous deux une définition de funct() et l'éditeur de liens ne savoir lequel utiliser dans votre programme et s’en plaindre.

Le correctif mentionné ci-dessus par Vaughn consiste à ne pas inclure le fichier cpp avec la définition de funct() dans mainfile.cpp, Mais à déplacer la déclaration de funct() dans un fichier d'en-tête séparé et incluez cela dans mainline.cpp. De cette façon, le compilateur obtiendra la déclaration de funct() et le lieur obtiendra une seule définition de funct() à partir de fun.cpp Et l'utilisera en toute confiance.

59
Mohit Chugh

Le problème est que si vous incluez fun.cpp à deux endroits de votre programme, vous finirez par le définir deux fois, ce qui n’est pas valide.

Vous ne voulez pas inclure les fichiers cpp. Vous souhaitez inclure des fichiers d'en-tête.

Le fichier d'en-tête doit simplement contenir la définition de la classe. Le fichier cpp correspondant, que vous compilerez séparément, aura la définition de la fonction.

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;
}

Notez qu'il est généralement recommandé d'éviter using namespace std dans les fichiers d'en-tête.

26
Vaughn Cato