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.
Related
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);
I am working on a project, and I have used Xcode in the past, and it has been "acting up" lately (might be me). The following code is a test code for this question (not my project).
(Assume that all lexical/preprocessing/namespace directives are all there.)
In Foo.hpp
class Foo {
public:
Foo();
};
Foo::Foo() {
cout << "constructive" << endl;
}
Now, if I run a main that constructs a Foo object, it gives a linker error of duplicate symbol. How should I fix this?
The quick and dirty fix is to either write
inline Foo::Foo(){
or fully define the function in the class definition:
public:
Foo(){cout << "constructive" << endl;}
The better fix is to ensure that the constructor definition is only compiled in exactly one translation unit; i.e. put it in a source file.
You need to declare the function as inline:
class Foo {
public:
inline Foo();
};
or put it in a .cpp file, to ensure that it is defined in only one translation unit:
// foo.cpp
Foo::Foo() {
cout << "constructive" << endl;
}
Oh, looks like I found the answer. All I did is delete Foo.cpp and it solved the problem. Also, I could have put the definitions in the .cpp file, but sending that to people isn't the best.
My new question is why does this work?
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
I've found some strange code...
//in file ClassA.h:
class ClassA {
public:
void Enable( bool enable );
};
//in file ClassA.cpp
#include <ClassA.h>
void ClassA::Enable( bool enable = true )
{
//implementation is irrelevant
}
//in Consumer.cpp
#include <ClassA.h>
....
ClassA classA;
classA.Enable( true );
Obviously since Consumer.cpp only included ClassA.h and not ClassA.cpp the compiler will not be able to see that the parameter has a default value.
When would the declared default value of ClassA::Enable in the signature of the method implementation have any effect? Would this only happen when the method is called from within files that include the ClassA.cpp?
Default values are just a compile time thing. There's no such thing as default value in compiled code (no metadata or things like that). It's basically a compiler replacement for "if you don't write anything, I'll specify that for you." So, if the compiler can't see the default value, it assumes there's not one.
Demo:
// test.h
class Test { public: int testing(int input); };
// main.cpp
#include <iostream>
// removing the default value here will cause an error in the call in `main`:
class Test { public: int testing(int input = 42); };
int f();
int main() {
Test t;
std::cout << t.testing() // 42
<< " " << f() // 1000
<< std::endl;
return 0;
}
// test.cpp
#include "test.h"
int Test::testing(int input = 1000) { return input; }
int f() { Test t; return t.testing(); }
Test:
g++ main.cpp test.cpp
./a.out
Let me admit first that this is the first time I have seen this type of code. Putting a default value in header file IS the normal practice but this isn't.
My guess is that this default value can only be used from code written in the same file and this way the programmer who wrote this wanted to put it in some type of easiness in calling the function but he didn't want to disturb the interface (the header file) visible to the outside world.
Would this only happen when the method
is called from within files that
include the ClassA.cpp?
That's correct. But note that doing so will almost certainly produce multiple definition errors, so the default is only really available from its point of definition within ClassA.cpp.
Put the default value in the declaration, not the definition.
class ClassA {
public:
void Enable( bool enable = true );
};
Playing around with MSVC++ 2005, I noticed that if the same class is defined several times, the program still happily links, even at the highest warning level. I find it surprising, how comes this is not an error?
module_a.cpp:
#include <iostream>
struct Foo {
const char * Bar() { return "MODULE_A"; }
};
void TestA() { std::cout << "TestA: " << Foo().Bar() << std::endl; }
module_b.cpp:
#include <iostream>
struct Foo {
const char * Bar() { return "MODULE_B"; }
};
void TestB() { std::cout << "TestB: " << Foo().Bar() << std::endl; }
main.cpp:
void TestA();
void TestB();
int main() {
TestA();
TestB();
}
And the output is:
TestA: MODULE_A
TestB: MODULE_A
It is an error - the code breaks the C++ One Definition Rule. If you do that, the standard says you get undefined behaviour.
The code links, because if you had:
struct Foo {
const char * Bar() { return "MODULE_B"; }
};
in both modules there would NOT be a ODR violation - after all, this is basically what #including a header does. The violation comes because your definitions are different ( the other one contains the string "MODULE_A") but there is no way for the linker (which just looks at class/function names) to detect this.
The compiler might consider that the object is useless besides its use in Test#() function and hence inlines the whole thing. That way, the linker would never see that either class even existed ! Just an idea, though.
Or somehow, linking between TestA and class Foo[#] would be done inside compilation. There would be a conflict if linker was looking for class Foo (multiple definition), but the linker simply does not look for it !
Do you have linking errors if compiling in debug mode with no optimizations enabled ?