Multiple definitions

I don't understand why I'm getting this error, as I've only defined it once, even if I remove the function prototype the error remains.

1
2
3
4
5
6
7
8
9
10
11
12
...
namespace zyx
{
    float degreesToRadians(float, const float);
    ...
    float degreesToRadians(float argDegrees, const float argPi = 3.14159265)
    {
        return argDegrees * (argPi / 180);
    }
    ...
}
...
Is it multiply defined in one file, or is the error that it is defined in more than one file?
Last edited on
It doesn't really say, or I can't read it.

1
2
3
4
5
6
7
8
obj\Debug\src\Vector.o||In function `_ZN3zge16radiansToDegreesEff':|
D:\Programming\C++\Projects\SFML\Asteroids\include\Vector.hpp|10|multiple definition of `zge::radiansToDegrees(float, float)'|
obj\Debug\main.o:D:\Programming\C++\Projects\SFML\Asteroids\include\Vector.hpp|10|first defined here|
obj\Debug\src\Vector.o||In function `_ZN3zge16degreesToRadiansEff':|
D:\Programming\C++\Projects\SFML\Asteroids\include\Vector.hpp|15|multiple definition of `zge::degreesToRadians(float, float)'|
obj\Debug\main.o:D:\Programming\C++\Projects\SFML\Asteroids\include\Vector.hpp|15|first defined here|
||=== Build finished: 4 errors, 0 warnings (0 minutes, 0 seconds) ===|


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#ifndef VECTOR_HPP
#define VECTOR_HPP

namespace zge
{
    float radiansToDegrees(float, const float);
    float degreesToRadians(float, const float);

    float radiansToDegrees(float argRadians, const float argPi = 3.14159265)
    {
        return argRadians * (180 / argPi);
    }

    float degreesToRadians(float argDegrees, const float argPi = 3.14159265)
    {
        return argDegrees * (argPi / 180);
    }

    struct Vector
    {
    public:
        Vector(float x = 0, float y = 0);
        Vector& operator=(const Vector& vec);
        Vector operator+(const Vector& vec);
        Vector& operator+=(const Vector& vec);
        Vector operator-(const Vector& vec);
        Vector& operator-=(const Vector& vec);
        Vector operator*(const Vector& vec);
        Vector& operator*=(const Vector& vec);
        Vector operator/(const Vector& vec);
        Vector& operator/=(const Vector& vec);

        Vector operator*(const float scalar);
        Vector& operator*=(const float scalar);
        Vector operator/(const float scalar);
        Vector& operator/=(const float scalar);

        float x;
        float y;

        float dot(const Vector& vec);
        float length();
        float squaredLength();
        Vector unit();

        Vector left();
        Vector right();
        Vector rotatedWithDegrees(float degrees, const float pi = 3.14159265);
        Vector rotatedWithRadians(const float radians);
        float degrees(const float pi = 3.14159265);
        float radians();

    private:
    };
}


#endif 
You are defining it in a header file. You are then putting that header file into more than one cpp file. Thus, each cpp file contains the definition. Each cpp file is then compiled into a single object file. Then, the linker gathers up all the object files and jams them together, and discovers that it has more than one set of compiled code for the function. This is bad; there is no way to tell apart two functions with the same name and same parameters, so there is no way it could know which one it should use when you call the function, so it throws an error and stops.

This is why defining a function in a header file that will be included in more than one cpp file is a very bad idea.
I know a little about the build and link process, but I didn't think it would be defined multiple times, how do structs/classes get around that then? surely they are also defined multiple times.

How can I fix this? I did try to define it in the .cpp file before which seems to be the solution but it didn't work, but I'll give it another go.

okay, that did fix that error, but it also caused several others like last time, and I feel kinda stupid right now so if you could help with that too...thanks.


D:\Programming\C++\Projects\SFML\Asteroids\src\Vector.cpp|7|warning: no previous declaration for 'float radiansToDegrees(float, float)' [-Wmissing-declarations]|


 
double radians = zge::degreesToRadians(Rect.getRotation());



D:\Programming\C++\Projects\SFML\Asteroids\main.cpp|56|undefined reference to `zge::degreesToRadians(float, float)'|


header

1
2
3
4
namespace zge
{
    float radiansToDegrees(float, const float argPi = 3.14159265);
    float degreesToRadians(float, const float argPi = 3.14159265);


source

1
2
3
4
5
6
using namespace zge;

float radiansToDegrees(float argRadians, const float argPi)
{
    return argRadians * (180 / argPi);
}


Last edited on
I didn't think it would be defined multiple times, how do structs/classes get around that then? surely they are also defined multiple times.


When you define a struct or a class, you're not actually making anything. No code is created (barring static variables etc., which by their very nature are only created once), so you can put the definition in different cpp files and the linker does not find any identical code that it can't tell the difference between. All it does is explain to the compiler how to make an object of that type when it has to.

When you define a function, code is created, so defining it in more than one cpp file does leave the linker with identical sets of code and no way to tell them apart.
Adding inline will fix the problem.

1
2
3
4
5
6
7
8
9
    inline float radiansToDegrees(float argRadians, const float argPi = 3.14159265)
    {
        return argRadians * (180 / argPi);
    }

    inline float degreesToRadians(float argDegrees, const float argPi = 3.14159265)
    {
        return argDegrees * (argPi / 180);
    }


While you're at it, I would also drop the unnecessary declarations.

Andy

PS Regarding

This is why defining a function in a header file that will be included in more than one cpp file is a very bad idea.
The exception (in the C++ world) to this otherwise fine rule are small, inlined functions.

radiansToDegrees() and degressToRadians() are good examples of functions I would define in a header (as inline functions).

PPS Out of interest, why is the value of pi redefinable?
Last edited on
D:\Programming\C++\Projects\SFML\Asteroids\main.cpp|56|undefined reference to `zge::degreesToRadians(float, float)'|


This means that at this point, the compiler has no idea what this function is. The ways around this are to declare it in advance, or define it in advance.

Typically, the way to do this is to declare it in a header file, which is #include d at the top of each cpp file that needs to know, and to define the function it in one cpp file that is complied and linked with all the rest.

It is well worth your time learning what the compiler and linker do and how they work together to create an executable or library.
Last edited on
I thought I did declare it, in the header, which main includes.

Like I said I know a small amount, and I've looked in to it a bit, but I doubt I will ever remember every last process, I'm just not that interested in the underlying arcane-powers.

As for declaring it inline, I don't see how that would help, especially considering the compiler doesn't care if you want it inline or not.
Last edited on
Declaration:
float radiansToDegrees(float, const float);

Definition:
1
2
3
4
float radiansToDegrees(float argRadians, const float argPi = 3.14159265)
{
    return argRadians * (180 / argPi);
}
The Declaration goes in the header file, where it may be included in the various other files.
The Definition goes just once in a .cpp file.
Last edited on
Which is.. what I've done?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#ifndef VECTOR_HPP
#define VECTOR_HPP

namespace zge
{
    float radiansToDegrees(float, const float argPi = 3.14159265);
    float degreesToRadians(float, const float argPi = 3.14159265);

    struct Vector
    {
    public:
        Vector(float x = 0, float y = 0);
        Vector& operator=(const Vector& vec);
        Vector operator+(const Vector& vec);
        Vector& operator+=(const Vector& vec);
        Vector operator-(const Vector& vec);
        Vector& operator-=(const Vector& vec);
        Vector operator*(const Vector& vec);
        Vector& operator*=(const Vector& vec);
        Vector operator/(const Vector& vec);
        Vector& operator/=(const Vector& vec);

        Vector operator*(const float scalar);
        Vector& operator*=(const float scalar);
        Vector operator/(const float scalar);
        Vector& operator/=(const float scalar);

        float x;
        float y;

        float dot(const Vector& vec);
        float length();
        float squaredLength();
        Vector unit();

        Vector left();
        Vector right();
        Vector rotatedWithDegrees(float degrees, const float pi = 3.14159265);
        Vector rotatedWithRadians(const float radians);
        float degrees(const float pi = 3.14159265);
        float radians();

    private:
    };
}


#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "Vector.hpp"
#include <iostream>
#include <cmath>

using namespace zge;

float radiansToDegrees(float argRadians, const float argPi)
{
    return argRadians * (180 / argPi);
}

float degreesToRadians(float argDegrees, const float argPi)
{
    return argDegrees * (argPi / 180);
}
...
Personally, I would put radiansToDegrees() and degressToRadians() back in the header as inline functions.

(This is because they are both tiny, readily inlinable functions)

See my earlier post.

Andy
Last edited on
1
2
3
4
5
6
7
8
9
float zge::radiansToDegrees(float argRadians, const float argPi)
{
    return argRadians * (180 / argPi);
}

float zge::degreesToRadians(float argDegrees, const float argPi)
{
    return argDegrees * (argPi / 180);
}
As for declaring it inline, I don't see how that would help, especially considering the compiler doesn't care if you want it inline or not.


as for why you can change pi.. well, I'm not 100% sure. Since pi is never ending someone might think of pi as 3.14, or 3.1415, or 3.141592653..blah..blah..., and if its not the same then there will be small errors in the calculations, maybe there isn't any point, I can easily remove it later if I decide to.
Last edited on
Ah nice, thanks Moschops, but why did I have to type the namespace with the resolution operator? I already 'said' I was using namespace zge, so is it normally float zge::zge::radiansToDegrees(float argRadians, const float argPi)?
Last edited on
using namespace zge;
tells the compiler that when it can't find something, it should look in namespace zge and see if it is in there. It certainly does not mean "everything that follows this line is inside namespace zge". That would be silly; what would you do if you had more than one using directive at the top, for example?

This:
1
2
3
4
float radiansToDegrees(float argRadians, const float argPi)
{
    return argRadians * (180 / argPi);
}

simply defines a function. It has nothing at all to do with namespaces.

This:
1
2
3
4
float zge::radiansToDegrees(float argRadians, const float argPi)
{
    return argRadians * (180 / argPi);
}

defines a function and specifies that this function lives inside the zge namespace.
#1 By marking the functions as inline it means you can define them in a header without hitting the mulitple definition problem. This "trick" is, of course, only suitable for small functions like the ones above.

#2 A float variable only has a limited number of significant figures. So you can work out how much "pi" it can handle.

Note that double is more commonly used for floating point numbers than float these days.

Andy

PS float variable can hold 7.22 decimal significant figures (they actually hold 23 bits)
http://www.stata.com/support/faqs/data-management/float-data-type/

rounding up to 8 for luck, that means the most pi they can hold is
3.1415927 (rounded to 8 sf)
Last edited on
But, I declared it inside the zge namespace in my header, so when it couldn't find radiansToDegrees, shouldn't it have looked in the zge namespace which was included when I included the header?
But, I declared it inside the zge namespace in my header, so when it couldn't find radiansToDegrees, shouldn't it have looked in the zge namespace which was included when I included the header?


It did, but you had not defined a function in the namespace zge with that name. There was no such function defined inside the namespace.

You had declared it, but when you defined it, you didn't define it inside any namespace. The function was just a global function at the top level, and you told the compiler that you had put the function inside the zge namespace.

This is exactly what namespaces are for; so you can have functions with the same name, and by putting them in different namespaces you can keep them distinct.

Here is what you did:

Declare them to be inside namespace zge:
1
2
3
4
5
namespace zge
{
    float radiansToDegrees(float, const float argPi = 3.14159265);
    float degreesToRadians(float, const float argPi = 3.14159265);
}




Defining them outside namespace zge...
1
2
3
4
5
6
7
8
9
10
11
using namespace zge;

float radiansToDegrees(float argRadians, const float argPi)
{
    return argRadians * (180 / argPi);
}

float degreesToRadians(float argDegrees, const float argPi)
{
    return argDegrees * (argPi / 180);
}




Trying to use the function inside zge, which has never been written. Only the one outside zge has been written, but the compiler won't use that one because you have very clearly said that this function is the one from inside namespace zge.
double radians = zge::degreesToRadians(Rect.getRotation());


So you created the function outside the namespace zge, but then told the compiler to use the one from inside the namespace - which has never been written.


Last edited on
Ah I see! I didn't realise I was creating it outside of the namespace, thanks.
Topic archived. No new replies allowed.