66

I am trying to relearn C++ after taking an intro course a few years ago and I’m having some basic problems. My current problem occurs when trying to use a friend function. Here is my code in 2 files.

First:

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

Second:

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

The error I am getting is "multiple definition of `funct()'". Am I using the wrong syntax when declaring it as a friend function?

awesoon
  • 32,469
  • 11
  • 74
  • 99
Adad Dayos
  • 701
  • 1
  • 5
  • 9

4 Answers4

94

Here is a highly simplified but hopefully relevant view of what happens when you build your code in C++.

C++ splits the load of generating machine executable code in following different phases -

  1. Preprocessing - This is where any macros - #defines etc you might be using get expanded.

  2. Compiling - Each cpp file along with all the #included files in that file directly or indirectly (together called a compilation unit) is converted into machine readable object code.

    This is where C++ also checks that all functions defined (i.e. containing a body in { } e.g. void Foo( int x){ return Boo(x); }) are referring to other functions in a valid manner.

    The way it does that is by insisting that you provide at least a declaration of these other functions (e.g. void Boo(int); ) before you call it so it can check that you are calling it properly among other things. This can be done either directly in the cpp file where it is called or usually in an included header file.

    Note that only the machine code that corresponds to functions defined in this cpp and included files gets built as the object (binary) version of this compilation unit (e.g. Foo) and not the ones that are merely declared (e.g. Boo).

  3. Linking - This is the stage where C++ goes hunting for stuff declared and called in each compilation unit and links it to the places where it is getting called. Now if there was no definition found of this function the linker gives up and errors out. Similarly if it finds multiple definitions of the same function signature (essentially the name and parameter types it takes) it also errors out as it considers it ambiguous and doesn't want to pick one arbitrarily.

The latter is what is happening in your case. By doing a #include of the fun.cpp file, both fun.cpp and mainfile.cpp have a definition of funct() and the linker doesn't know which one to use in your program and is complaining about it.

The fix as Vaughn mentioned above is to not include the cpp file with the definition of funct() in mainfile.cpp and instead move the declaration of funct() in a separate header file and include that in mainline.cpp. This way the compiler will get the declaration of funct() to work with and the linker would get just one definition of funct() from fun.cpp and will use it with confidence.

Campa
  • 4,267
  • 3
  • 37
  • 42
Mohit Chugh
  • 1,041
  • 6
  • 4
  • So have I understood this right: the _call_ to `funct();` within `mainfile.cpp:main()` counts as a definition of `funct()`? – Martin Smith Apr 22 '22 at 11:02
  • 2
    @MartinSmith I was drawn to the same conclusion until a coworker corrected me: no, rather, it's that the inclusion of `fun.cpp` into `mainfile.cpp` creates *two* `funct()` definitions (one in `fun.cpp` and one in `mainfile.cpp`). Including `fun.cpp` copies-and-pastes its contents into `mainfile.cpp`, including `funct()`'s definition. That's why it's bad practice to include implementation files instead of header files. : p – 6equj5 Sep 21 '22 at 16:57
40

The problem is that if you include fun.cpp in two places in your program, you will end up defining it twice, which isn't valid.

You don't want to include cpp files. You want to include header files.

The header file should just have the class definition. The corresponding cpp file, which you will compile separately, will have the function definition.

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

Note that it is generally recommended to avoid using namespace std in header files.

Vaughn Cato
  • 63,448
  • 5
  • 82
  • 132
  • 3
    Also it can help with some linkers to wrap header guards -- search on #ifndef – Neil Neyman Jul 28 '13 at 03:33
  • 1
    @CarlNorum I was under the impression that multiple definition errors were linker errors not compilation. But perhaps I'm mistaken. – Neil Neyman Jul 28 '13 at 04:08
  • 3
    They are, but header guards don't have anything to do with that. Well, unless you do something crazy in your headers, that is. – Carl Norum Jul 28 '13 at 04:28
  • 3
    Why does it work for classes and not functions ? I don't see what is special about a function compared to a class definition that requires it to be placed in a cpp file. – ElefEnt Apr 17 '15 at 17:00
  • 2
    @ElefEnt: A class is purely a compile-time entity. If you have a class defined that you never use, then no machine code will be created by the compiler. However a non-inline function definition implies actually creating machine code, whether you use it or not. You only want that machine code to be stored in one object file. If you were to place the function definition in the header, it would imply creating machine code wherever that header was included. – Vaughn Cato Apr 18 '15 at 15:06
  • 1
    @CarlNorum - compilers? No. Preprocessors, sure. – aerkenemesis Nov 22 '16 at 20:36
1

This problem happens because you are calling fun.cpp instead of fun.hpp. So c++ compiler finds func.cpp definition twice and throws this error.

Change line 3 of your main.cpp file, from #include "fun.cpp" to #include "fun.hpp" .

new Q Open Wid
  • 2,225
  • 2
  • 18
  • 34
jelambrar
  • 39
  • 3
1

You have #include "fun.cpp" in mainfile.cpp so compiling with:

g++ -o hw1 mainfile.cpp

will work, however if you compile by linking these together like

g++ -g -std=c++11 -Wall -pedantic   -c -o fun.o fun.cpp
g++ -g -std=c++11 -Wall -pedantic   -c -o mainfile.o mainfile.cpp

As they mention above, adding #include "fun.hpp" will need to be done or it won't work. However, your case with the funct() function is slightly different than my problem.

I had this issue when doing a HW assignment and the autograder compiled by the lower bash recipe, yet locally it worked using the upper bash.

Greenonline
  • 1,330
  • 8
  • 23
  • 31
Michael Kaufman
  • 312
  • 3
  • 4