LNK1169 one or more multiply defined symbols found And LNK2005 - c++

I encountered this problem when I try to compile my code
I thought it might be caused by header files including each other. But as far as I can tell I did not find any issues with my header files
Error LNK1169 one or more multiply defined symbols
found Homework2 D:\05Development\04 C_C++\C\DS Alg
class\Homework2\Debug\Homework2.exe 1
also, there's an error telling me that function Assert() has been declared elsewhere.
Error LNK2005 "void __cdecl Assert(bool,class
std::basic_string,class
std::allocator >)"
(?Assert##YAX_NV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###Z)
already defined in DataBase.obj Homework2 D:\05Development\04
C_C++\C\DS Alg class\Homework2\Homework2\dbTest.obj 1
here's the structure of my code:
function
void Assert(bool val, string s)
{
if (!val)
{
cout << "Assertion Failed!!: " << s << endl;
exit(-1);
}
}
is in Constants.h
A virtual class List includes Constants.h
#pragma once // List.h
#include "Constants.h"
An array list includes List class, in the AList class it calls the Assert function
#pragma once //AList.h
#include "List.h"
...
Assert((pos >= 0) && (pos < listSize), "Position out of range");
In the DataBase class I created a AList member
private:
AList<CData> set;
header looks like this:
#pragma once
#include "AList.h"
#include "CData.h"
and CData.h looks like this:
#pragma once
class CData
{
private:
std::string m_name;
int m_x;
int m_y;
public:
CData(std::string str = "null", int x = 0, int y = 0) : m_name(str), m_x(x), m_y(y) {}
// Helper functions
const std::string& GetName() const { return this->m_name; }
const int& GetX() const { return this->m_x; }
const int& GetY() const { return this->m_y; }
};

When you build your project, each .cpp file gets compiled separately into different object files. The once in #pragma once only applies to the compilation of a single .cpp file, not for the project as a whole. Thus if a .cpp file includes header A and header B, and header B also includes header A, then the second include of header A will be skipped.
However, if you have another .cpp file that includes A, A will be included in that object file again -- because #pragma once only works when compiling a single .cpp file.
An #include statement literally takes the content of the included file and "pastes" it into the file that included it. You can try this by looking at the output of the C preprocessor tool (cpp in the gcc toolchain). If you are using the gcc toolchain, you can try something like this to see the file after its includes have been applied:
cpp file.cpp -o file_with_includes.cpp
If you have a function in your header, like Assert in your example, the function gets replicated into each .cpp file you include it in.
If you have A.cpp and B.cpp, that both include your Constants.h file, each object file (.o or .obj depending on your environment) will include a copy of your Assert function. When the linker combines the object files to create a binary, both object files will declare that they provide the definition for Assert, and the linker will complain, because it doesn't know which one to use.
The solution here is either to inline your Assert function, like this:
inline void Assert(bool val, string s)
{
if (!val)
{
cout << "Assertion Failed!!: " << s << endl;
exit(-1);
}
}
or to provide its body in its own .cpp file, leaving only the function prototype in the header.
Constants.h:
void Assert(bool val, string s);
Constants.cpp:
void Assert(bool val, string s)
{
if (!val)
{
cout << "Assertion Failed!!: " << s << endl;
exit(-1);
}
}
Mind you, the Standard Library also offers assert(), which works nicely too. (see https://en.cppreference.com/w/cpp/error/assert).
#include <cassert>
...
assert(is_my_condition_true());
assert(my_variable > 23);
// etc..
Just keep in mind that the assert declared in cassert only works when compiling for Debug, and gets compiled out when building for Release (to speed up execution), so don't put any code in assert that has side effects.
#include <cassert>
...
// Don't call functions with side effects.
// Thus function decreases a "count" and returns the new value
// In Release builds, this line will disappear and the decrement
// won't occur.
assert(myclass.decrement_count() > 0);

Related

Question about referencing a class from a different source file in C++

I was recently having some "undefined reference" errors that I managed to resolve but I don't understand why the solution works. I have the following main source file:
Main.cpp:
#include <iostream>
#include "Log.h"
int main()
{
std::cout << "Hello World!" << std::endl;
Log log;
log.SetLevel(Log::LevelWarning);
log.Error("Hello!");
log.Warning("Hello!");
log.Info("Hello!");
std::cin.get();
}
which references a class declared in a separate source file:
Log.cpp:
#include <iostream>
class Log
{
public:
enum Level
{
LevelError, LevelWarning, LevelInfo
};
private:
Level m_LogLevel = LevelInfo;
public:
void SetLevel (Level level)
{
m_LogLevel = level;
}
void Error (const char* message)
{
if (m_LogLevel >= LevelError)
std::cout << "[ERROR]: " << message << std::endl;
}
void Warning (const char* message)
{
if (m_LogLevel >= LevelWarning)
std::cout << "[WARNING]: " << message << std::endl;
}
void Info (const char* message)
{
if (m_LogLevel >= LevelInfo)
std::cout << "[INFO]: " << message << std::endl;
}
};
Log.h:
#pragma once
class Log
{
public:
enum Level { LevelError, LevelWarning, LevelInfo };
private:
Level m_LogLevel;
public:
void SetLevel (Level);
void Error (const char*);
void Warning (const char*);
void Info (const char*);
};
The code above gives me the linker errors "undefined reference to Log::..." for all members of the class Log being called in Main.cpp. Searching around I eventually found comment saying something along the lines of "static members and functions should be initialized", which gave me the idea of adding the following:
void Init()
{
Log log;
log.SetLevel(Log::LevelInfo);
log.Error("NULL");
log.Warning("NULL");
log.Info("NULL");
}
To my Log.cpp file. This amazingly solves the issue and the project builds successfully, but these members are not declared as static and so I don't understand why this works, or even if this is the correct solution.
I'm using gcc in linux and compiling with "g++ Main.cpp Log.cpp -o main". Source files are in the same folder.
c++ is not java or c#. This construct won't generate any code at all:
class X
{
public:
void foo()
{
std::cout << "Hello, world"<< std::endl;
}
};
Yes, in java after compiling that you will get X.class which you can use. However in c++ this does not produce anything.
proof:
#include <stdio.h>
class X
{
void foo()
{
printf("X");
}
};
$ gcc -S main.cpp
$ cat main.s
.file "main.cpp"
.ident "GCC: (GNU) 4.9.3"
.section .note.GNU-stack,"",#progbits
In c++ you need something other than "definitions" for anything to be compiled.
If you want to emulate java-like compiler behaviour do this:
class X
{
public:
void foo();
};
void X::foo()
{
std::cout << "Hello, world"<< std::endl;
}
this will generate object file containing void X::foo().
proof:
$ gcc -c test.cpp
$ nm --demangle test.o
0000000000000000 T X::foo()
Another option is of course use inline method as you do but in this case you would need to #include whole "Log.cpp" into your "Main.cpp".
In c++ compilation is done by "translation units" instead of classes. One unit (say .cpp) produces one object file (.o). Such object file contains machine instructions and data.
Compiler does not see anything outside of a translation unit being compiled now.
Thereofre, unlike Java when main.cpp is compiled compiler only sees what is #included into main.cpp and main.cpp itself. Hence the compiler do not see the contents of Log.cpp at this time.
It's only at link time object files generated from translation units are merged together. But at this time it's too late to compile anything.
A class with inline function (like the first example) does not define any machine instructions or data.
For inline members of class machine instructions will be generated only when you use them.
Since you use your class members in main.cpp which is outside of translation unit Log.cpp during compilation of Log.cpp compiler does not generate any machine instructions for them.
Problem of One Definition Rule is a different one.
Your code is not correctly organized. You should not have two different class Log { ... }; contents for the same class.
Main.cpp needs to know the contents of class Log, so the (single) definition of class Log will need to be in your header file. That leaves the question of the definitions of the class member functions. There are three ways to define a class member function:
Inside the class definition (which is in a header).
This is what you attempted in your Log.cpp file. If you define all the members in the class definition in Log.h, then you don't need a Log.cpp file at all.
Outside the class definition, with the inline keyword, in the header file.
This would look like:
// Log.h
class Log
{
// ...
public:
void SetLevel(Level level);
// ...
};
inline void Log::SetLevel(Level level)
{
m_LogLevel = level;
}
Outside the class definition, with no inline keyword, in the source file.
This would look like:
// Log.h
class Log
{
// ...
public:
void SetLevel(Level level);
// ...
};
// Log.cpp
#include "Log.h"
void Log::SetLevel(Level level)
{
m_LogLevel = level;
}
Note Log.cpp includes Log.h, so that the compiler sees the class definition before you start trying to define its members.
You are allowed to mix and match these. Although there are no strict rules on what is best, a general guideline is that small and simple functions can go in the header file, and large and complex functions might do better in the source file. Some programmers recommend not putting any function definitions inside the class definition at all, or limiting this option to cases where the definition is very short and helps make clear what the purpose of the function is, since then the (public part of the) class definition is a summary of what the class does, not details about how it does it.
In some cases, it might be appropriate to define a class inside a source *.cpp file - but this means it can only be used from that file.

'Render': 'class' type redefinition (C2011)

There are a lot of similar questions on Stack Overflow, regarding this topic.
I am creating a project with multiple files (.cpp and .h). I am getting the error:
C2011: 'Render': 'class' type redefinition
I have read about it. Some people are saying use guards, so I am using #pragma once on all header files. Some people say the header is being included multiple times, but the guards will prevent that. So what am I doing wrong?
Code:
Cubes.h
#pragma once
char orientation(int sides, int hV);
std::vector<char> visOrd(std::string *xOrd, int *pov, int ord);
std::vector<int> convertColour(std::vector<std::string> rlBoxCol);
std::tuple<std::vector<int>, std::vector<std::string>> organiseLayers(std::vector<int> boxCoords, std::vector<std::string> rlBoxCol, std::vector<float> rot);
class Render
{
private:
std::vector<float> rot;
std::vector<int> boxCoords;
std::vector<std::string> rlBoxCol;
int gridSize;
int cubeSize;
std::vector<int> offset;
public:
Render();
void setRotation(std::vector<float> setRot);
std::vector<float> getRotation();
void setCoordinates(std::vector<int> setBoxCoords);
std::vector<int> getCoordinates();
void setColours(std::vector<std::string> setRlBoxCol);
std::vector<std::string> getColours();
void setSizeOfGrid(int setGridSize);
int getSizeOfGrid();
void setSizeOfCubes(int setCubeSize);
int getSizeOfCubes();
void setOffset(std::vector<int> setOffset);
std::vector<int> getOffset();
void display();
};
Cubes.cpp
#include "Cubes.h"
#include "Global.h"
char orientation(int sides, int hV)
{
// Code
}
std::vector<char> visOrd(std::string *xOrd, int *pov, int ord)
{
// Code
}
std::vector<int> convertColour(std::vector<std::string> rlBoxCol)
{
// Code
}
std::tuple<std::vector<int>, std::vector<std::string>> organiseLayers(std::vector<int> boxCoords, std::vector<std::string> rlBoxCol, std::vector<float> rot)
{
// Code
}
Render::Render()
{
this->rot;
this->boxCoords;
this->rlBoxCol;
this->gridSize;
this->cubeSize;
this->offset;
}
void Render::setRotation(std::vector<float> setRot)
{ // Set rotation
rot = setRot;
}
std::vector<float> Render::getRotation()
{ // Get rotation
return rot;
}
void Render::setCoordinates(std::vector<int> setBoxCoords)
{
boxCoords = setBoxCoords;
}
std::vector<int> Render::getCoordinates()
{
return boxCoords;
}
void Render::setColours(std::vector<std::string> setRlBoxCol)
{
rlBoxCol = setRlBoxCol;
}
std::vector<std::string> Render::getColours()
{
return rlBoxCol;
}
void Render::setSizeOfGrid(int setGridSize)
{
gridSize = setGridSize;
}
int Render::getSizeOfGrid()
{
return gridSize;
}
void Render::setSizeOfCubes(int setCubeSize)
{
cubeSize = setCubeSize;
}
int Render::getSizeOfCubes()
{
return cubeSize;
}
void Render::setOffset(std::vector<int> setOffset)
{
offset = setOffset;
}
std::vector<int> Render::getOffset()
{
return offset;
}
void Render::display()
{
// Drawing code
}
EDIT:
I have now changed the code in ways you said. Now I am getting errors LNK2005 and LNK1169. What's gone wrong now?
EDIT 2: (Errors)
LNK2005
"class sf::RenderWindow Window" (?Window##3VRenderWindow#sf##A) already defined in Cubes.obj
C:\Users\George\Documents\C++\Projects\Don't fall\Don't fall\main.obj 1
.
LNK2005
"class std::basic_string,class std::allocator > status" (?status##3V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##A) already defined in Cubes.obj
C:\Users\George\Documents\C++\Projects\Don't fall\Don't fall\main.obj 1
.
LNK1169
one or more multiply defined symbols found
C:\Users\George\Documents\C++\Projects\Don't fall\Debug\Don't fall.exe 1
Global.h:
#pragma once
#include <SFML\Graphics.hpp>
// This is where all my global variables will be
extern sf::RenderWindow Window(sf::VideoMode(500, 500), "Maximize window to play the game");
extern std::string status = "NULL";
Your Cubes.cpp does redefine the class Render. In general the .h file has the class prototype and the .cpp defines the methods.
Try adding this to the top of the Cubes.cpp:
#include "Cubes.h"
removing this from the top of Cubes.cpp:
class Render
{
private:
std::vector<float> rot;
std::vector<int> boxCoords;
std::vector<std::string> rlBoxCol;
int gridSize;
int cubeSize;
std::vector<int> offset;
public:
and removing this from the bottom:
};
This is not how you provide the implementation of a class in C++. The keyword class defines the class, which is what you have in your header (.h file). In the .cpp file you wish to implement the methods which you defined in your header file, so you should not redefine the entire class. Rather, you need to provide implementations for the methods (member functions) of the class, like so:
void Render::setRotation(std::vector<float> setRot)
{ // Set rotation
rot = setRot;
}
std::vector<float> Render::getRotation()
{ // Get rotation
return rot;
}
Notice the prefix Render::? This is how you indicate that you are providing an implementation for the function setRotation of the class Render. Just add the function implementation like this in your cpp, do not nest them within a class, do not include any fields (the member fields have already been defined in the header, they are done).
Update:
OK, so according to the updated answer your linker error refers to the instances sf::RenderWindow Window and std::string status; this error occurs when linking main.obj (from main.cpp?) with Cubes.obj. The error is telling you that both main.obj and Cubes.obj define these variables.
I recommend that you read about "Compilation Units" in C++ and difference between declaration and definition of a symbol; but to give a very brief summary:
Essentially, the compiler runs on a single "compilation unit"; you can think of it as a single file. What the #include-statement does is basically copy/paste the content of the included file into the compilation unit. So when you compile Cubes.cpp, it will go through all of the nested includes until it has generated one huge cpp-file with everything included. Then it will build this into an .obj file. Then you do the same thing with main.cpp, and any other .cpp files you might have. Finally, the linker will attempt to link these object files together to produce the final result.
Now, if the linker finds duplicate definitions when linking two objects you will get an error. So you cannot have two global variables with the same name! If both Cubes.cpp and main.cpp include global.h, then both compilation units contain global variable definitions Window and status. This is causing your linker error.
This is why you put a declaration in the header (since it is included in multiple compilation units), and the definition in the source file (typically not included elsewhere). You build the source file to produce the only object file containing the definition; all other object files only reference the declaration. The linker can then link those references to the definition found in one the object files.
So you want to declare the variables in the header, and move the definition somewhere else. For instance, to main.cpp; but that depends entirely on the rest of your application and what you are trying to achieve. Outside the scope of the question.

Troubles with compiling, static initialization and static libraries

I have recently encountered a behavior in C++ program that I cannot entirely understand. Let me explain the behavior via simple example.
1. First static library
At the very bottom of hierarchy, I have a static library - lets name it FirstLIB. This library includes two pairs of header/source files. The sample.h header file contains MyClass class definition. Corresponding sample.cpp file contains implementation of this class (its methods). The code is presented below:
sample.h
#ifndef __sample_h
#define __sample_h
namespace SampleNamespace
{
class MyClass
{
int counter;
public:
MyClass();
int GetCounter();
void SetCounter(int value);
};
}
#endif
and sample.cpp
#include <iostream>
#include "sample.h"
namespace SampleNamespace
{
MyClass::MyClass(): counter(0)
{
std::cout << "Inside of MyClass constructor!" << std::endl;
}
int MyClass::GetCounter() { return counter; }
void MyClass::SetCounter(int value) { counter = value; }
}
Onwards, the dvcl.h file declares simple API used to manipulate MyClass object and dvcl.cpp implements this API. It's important to notice that dvcl.cpp file contains definition of MyClass object that is used by the methods of this API. The variable is defines as static so it will be visible only inside of this source file.
dvcl.h
#ifndef _dvcl_h
#define _dvcl_h
void DVCL_Initialize(int counter);
int DVCL_GetCounter();
void DVCL_SetCounter(int value);
#endif
dvcl.cpp
#include "dvcl.h"
#include "sample.h"
static SampleNamespace::MyClass myClass;
void DVCL_Initialize(int counter)
{
myClass.SetCounter(counter);
}
int DVCL_GetCounter()
{
return myClass.GetCounter();
}
void DVCL_SetCounter(int value)
{
myClass.SetCounter(value);
}
2. Second static library
Second static library - lets name it SecondLIB - is even simpler than the first one. It only contains one header/source pair. The dvconference_client.h header declares one function, while dvconference_client.cpp implements this function. dvconference_client.cpp also includes dvcl.h header file (which will trigger compilation of dvcl.cpp source). The code can be found below:
dvconference_client.h
#ifndef __external_file
#define __external_file
int DoSomething();
#endif
dvconference.cpp
#include "dvconference_client.h"
#include "dvcl.h"
int DoSomething()
{
return DVCL_GetCounter();
}
3. Main executable
And finally, the main executable MainEXE includes only one main.cpp file. This source includes dvconference_client.h and dvcl.h headers. The code is presented below:
#include <iostream>
#include "dvconference_client.h"
#include "dvcl.h"
int main()
{
std::cout << DoSomething() << std::endl;
std::cout << DVCL_GetCounter() << std::endl;
return 0;
}
4. My doubts and questions:
If I don't call a function that references myClass object (so DoSomething() or one of DVCL_ functions), the MyClass constructor is not invoked. I expected that myClass object will be instantiated by default as dvcl.cpp is compiled. However, it appears that compiler generates needed statements only if it understand that object is actually used in runtime. Is this really true?
If particular header file (in this case dvcl.h) is included in different sources, the corresponding dvcl.cpp is compiled only once. I remember reading something about this, however I'm not sure that this is really true. Is it actually correct that C++ compiler will compile every source file only once, regardless of how many the corresponding header file is included.
myClass object defined in dvcl.cpp is instantiated only once. If I correctly understand the 2nd point and if dvcl.cpp is compiled only once, then there is nothing to question here.
I hope more experienced colleagues can clear my doubts (and I apologize for very long post).
"static SampleNamespace::MyClass myClass; " is both a declaration and definition. So your constructor is invoked and created. Asm-code to instantiate this is generated at compile-time but this is executed at executable-load-time.
For referenec, stages of compilation
source-code --> pre-processing --> compilation --> linking --> loading --> execution
Yes, ".c/.cpp" file are compiled only once. But header are parsed per inclusion.
Yes object is executed only once because corresponding object-file is linked and loaded only once.
First point :
dvcl compilation unit is in a static library. If the code is not used, the compiled object (.o) is not included in resulting executable. As such, static SampleNamespace::MyClass myClass; is never executed. It won't be the same if you were using a dynamic library or explicitely linking the .o file at link time.
Second point :
Use you or not libraries, a source file (.c) or (.cpp) is only compiled (and linked into the executable) once. That's the reason for having .h files that are included in other files and as such processed one time per including file
Third point :
The object is effectively instantiated once, since the .o file is linked only once

How to declare `#include` for a header file to avoid `error lnk2005`

I created a new WIN32 C++ project. I didn't touch any of the code in the main file yet, and started to write my code in a different file objectsFW.cpp the definitions for the file are located in the file objectsFW.h.
objFW.h looks like:
#pragma once
double g;
typedef struct {
double x;
double y;
}Vector;
typedef struct {
//...
}BoundingBox;
typedef struct {
//...
}Ball;
Vector operator + (Vector a, Vector b) {
//...
}
Vector operator - (Vector a, Vector b) {
//...
}
There are some more operators defined, and the declarations of the functions.
I included the header file in the source file (objectsFW.cpp), and also, added it to the Resources.h file, so that my code will be useable in the main program.
I get linker errors:
Error 1 error LNK2005: "struct Vector __cdecl operator*(struct Vector,double)" (??D#YA?AUVector##U0#N#Z) already defined in ObjectsFW.obj C:\testC\ObjectsCollision\ObjectsCollision\ObjectsCollision.obj ObjectsCollision
...
Error 4 error LNK2005: "struct Vector __cdecl operator+(struct Vector,struct Vector)" (??H#YA?AUVector##U0#0#Z) already defined in ObjectsFW.obj C:\testC\ObjectsCollision\ObjectsCollision\ObjectsCollision.obj ObjectsCollision
and so on.
I know that this happens because the #include "objectFW.h" line appears two times (once in each .cpp file). The question is what is the right way to declare the header file to avoid linker errors?
UPDATE:
After turning the operator functions to inline most of the errors fixed, there is still a program with the line:
double g;
the error is:
Error 1 error LNK2005: "double g" (?g##3NA) already defined in ObjectsCollision.obj C:\testC\ObjectsCollision\ObjectsCollision\ObjectsFW.obj ObjectsCollision
(working on Visual Studio 2012)
About global variables:
1. Refrain from using them. Think encapsulation and data hiding.
2. If you must use them, define the global in 1 source file and place the "extern" in a header file.
Example:
header_file.hpp:
extern unsigned int deadly_global;
source_file.cpp:
unsigned int deadly_global;
Better method for hiding global variables
A better method for controlling (hiding) global variables is to place all the code that uses the variable in the same source file and declare the variable as static:
static unsigned int variable_shared_by_many_functions = 0;
void f1(void)
{
variable_shared_by_many_functions = 42U;
}
void f2(void)
{
std::cout << "Value of shared variable: "
<< variable_shared_by_many_functions
<< "\n";
}
Controlling Global Variables Using Getters and Setters
If you must share the variable among functions in more than one source file, a safer technique is to declare the variable as static in one source file and declare functions (interfaces) to access it.
static int dangerous_variable = 0;
int accessor(void)
{
// Return a copy of the varible.
return dangerous_variable;
}
void setter(int new_value)
{
if ((new_value / 5) != 1)
{
dangerous_variable = new_value;
}
}
This technique allows you to place filters or other controls on setting the variable.
Put in your header:
extern double g;
And in a .cpp:
double g;
That way every file that includes the header will know that there is a variable g, but it will only be declared at one place.

How can I be getting "already defined" linker errors here?

I'm making my first attempt at unit testing in C++, and I haven't used C++ in a number of years (I'm mainly a C# coder at the moment). It seems like I'm making a right pig's ear of it - I hope someone can steer me back onto the righteous path. I'm just getting started here and would really like to be implementing these tests using the best practice possible, so any and all comments are welcome, even though I'm most concerned with my linker error at present.
So, I have an overall solution "Technorabble", with sub-projects "CalibrationTool" and "CalibrationToolUnitTests".
CalibrationTool has a MathUtils.h file:
#ifndef __math_utils__
#define __math_utils__
#include "stdafx.h"
#include <vector>
namespace Technorabble
{
namespace CalibrationTool
{
double GetDoubleVectorAverage(std::vector<double> v)
{
double cumulativeValue = 0;
for(std::vector<double>::iterator iter = v.begin(); iter != v.end(); ++iter)
{
cumulativeValue += *iter;
}
return cumulativeValue / v.size();
}
}; // end namespace CalibrationTool
}; // end namespace Technorabble
#endif // !__math_utils__
(But no .cpp file as I was having all kinds of (somewhat similar) issues getting my template function working - so I ended up defining that inline).
Moving on to the Unit Tests project, I have a main.cpp:
#include "MathUtilsTest.h"
void RunMathUtilsTests();
int main()
{
RunMathUtilsTests();
// Other class tests will go here when I have things to test
}
void RunMathUtilsTests()
{
MathUtilsTest* mathUtilsTest = new MathUtilsTest();
mathUtilsTest->RunTests();
delete mathUtilsTest;
}
Finally, the header and cpp for the MathUtilsTest class, again, fairly simple:
.h:
#ifndef __MATH_UTILS_TEST__
#define __MATH_UTILS_TEST__
#include "CalibrationToolUnitTestsLogging.h"
#include "..\CalibrationTool\MathUtils.h"
class MathUtilsTest
{
public:
MathUtilsTest();
~MathUtilsTest();
bool RunTests();
private:
bool GetDoubleVectorAverageTest();
}; // end class MathUtilsTest
#endif
.cpp:
#include "MathUtilsTest.h"
#include <sstream>
bool MathUtilsTest::RunTests()
{
return GetDoubleVectorAverageTest();
}
MathUtilsTest::~MathUtilsTest()
{
}
MathUtilsTest::MathUtilsTest()
{
}
bool MathUtilsTest::GetDoubleVectorAverageTest()
{
bool passed = true;
std::vector<double> values;
for (int i = 1; i < 23; i++)
{
values.push_back(i);
}
// vector becomes: 1, 2, 3, 4, .....20, 21, 22. Average is 11.5
double expectedAverage = 11.5;
double calculatedAverage = Technorabble::CalibrationTool::GetDoubleVectorAverage(values);
if (calculatedAverage != expectedAverage)
{
std::ostringstream s;
s << calculatedAverage;
std::string avgString = s.str();
CalibrationToolUnitTestsLogging::Write("Failed MathUtilsTest.GetDoubleVectorAverageTest: " + avgString);
passed = false;
}
else
{
CalibrationToolUnitTestsLogging::Write("Passed MathUtilsTest.GetDoubleVectorAverageTest");
}
return passed;
}
This all seemed fine to me, I'm protecting my header with #ifndef, etc. But I'm still getting the following errors:
1) error LNK1169: one or more multiply defined symbols found
2) error LNK2005: "double __cdecl Technorabble::CalibrationTool::GetDoubleVectorAverage(class std::vector >)" (?GetDoubleVectorAverage#CalibrationTool#Technorabble##YANV?$vector#NV?$allocator#N#std###std###Z) already defined in main.obj C:_SVN\Technorabble\Windows Software\CalibrationToolUnitTests\MathUtilsTest.obj
How can this be? Can anyone spot where it's going wrong?
Functions defined in headers should be marked as inline:
inline double GetDoubleVectorAverage(std::vector<double> v)
{
}
If it's longer than a couple of lines, consider moving it to an implementation file.
pragmas or include guards don't protect against multiple definitions.
Note that you should pass v by const reference rather than by-value.
You are defining a function GetDoubleVectorAverage in a header. This means that it will be defined in every translation unit (i.e. every source file) that includes that header. If your program contains more than one such translation unit, then you'll have more than one definition - which isn't allowed.
Solutions are:
Add inline to the function definition, to relax this rule and allow multiple identical definitions; or
Move the function definition into a source file, and only declare it in the header.
I'm protecting my header with #ifndef
That only prevents the header from being included more than once within the same translation unit. It doesn't prevent inclusion from more than one unit.
Also, you shouldn't use a reserved name like __math_utils__ as a header guard, even if the internet is littered with examples of dodgy code doing that.
I was having all kinds of (somewhat similar) issues getting my template function working
Templates usually need to be defined in header files, to make the definition available at the point of use. Function templates are implicitly inline, but normal functions (like this one) aren't.