Consider this code
#include <iostream>
#include <cstdio>
using namespace std;
class Dummy {
public:
Dummy();
};
inline Dummy::Dummy() {
printf("Wow! :Dummy rocks\n");
}
int main() {
Dummy d;
}
All is good here!
Now I do this modification. I move the declaration of Dummy to "dummy.h".
class Dummy {
public:
Dummy();
};
And define the constructor Dummy() as following in "dummy.cpp"
#include "dummy.h"
inline Dummy::Dummy() {
printf("Wow! :Dummy rocks\n");
}
And finally, I have my main file as:
#include <iostream>
#include <cstdio>
#include "dummy.h"
using namespace std;
int main() {
Dummy d;
}
It compiles fine, but I get a linker error complaining an undefined reference to Dummy::Dummy().
Any insights.
--
You have to put all inline functions (including methods and constructors/destructors) in a header file, where they are declared.
Though this code should work either way, with main() calling the constructor as if the inline keyword was not there. Are you sure you are passing object files from both compilation units to the linker?
You should think how compiling works at C++ and the idea of separate compiling units used at C++ and encapsulation gained using headers and cpp files.
Look here:
http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.6
The inline tells the complier that instead of calling the function to "copy - paste" its code at the place of the function call. When you put the inline definition in a CPP file it won't be visible during linking to other compiled units (its in cpp file not in h file) so the compiler understand from the signature placed at the class that there is no-paramter Con's so it won't implement the default one. But the linker can't find the function body cause it is implemnted inline at the cpp file.
Try removing the inline specifier from the your implementation file. If my understanding is correct, you can only inline in a header
Related
I'm trying to create a library for a school work, and I've been wondering if it is safe to declare a templated class on the main header file containing the class definition and method declarations, but then separating the method definitions in a different header file?
Because I have been able to do this in my example below, but I don't know if it will cause me some problems in the long run.
main program
// main.cpp
#include <iostream>
#include "declaration.hpp"
int main()
{
card<int> a(5);
std::cout<<a.getID()<<'\n';
return 0;
}
main header file
in this header file, only the class definition and the declaration of the method getID() is written but not it's definition, and by the end of the class I included the other header file that contains the method definitions.
// declaration.hpp
#ifndef DEC_HPP
#define DEC_HPP
#include <iostream>
template<typename T>
class card
{
public:
T id;
card(const int id) : id(id) {}
T getID();
};
#include "definition.hpp"
#endif
method definitions
This header file contains the method definition of getID() from the main header.
I also included the "declaration.hpp" in this header, and this is the part where I'm not so sure of, because I included both files together with each other.
// definitions.hpp
#ifndef DEF_HPP
#define DEF_HPP
#include <iostream>
#include "declaration.hpp"
template<typename T>
T card<T>::getID()
{
return id;
}
#endif
I have compiled this program and it's working on my machine, but I just wanted to know if this way of isolating my code will cause me some errors in the future, I don't want to put my templated class definitions in a cpp files because I find it hard to maintain.
This is indeed a better approach because it makes your code look simple and better. Moreover, it is the main reason why header file is used.
Your main header file will simply tell that what functions/classes are you using and without even viewing your code, anyone can guess if you are working correctly or not.
There wont be any safety issues at all.
gcc version 5.4.0 (GCC)
> g++ -std=c++11
During a build I get a multiply defined error message for a class constructor. When I delete the constructor, I get an undefined symbol error message. I'm stumped.
NodeClass::NodeClass( ... ) is marked as
Error Message:
build/Debug/Cygwin64-Windows/nodeClass.o: In function `__gnu_cxx::new_allocator<std::string*>::~new_allocator()':
/c/home/skidmarks/Projects/MPHASH/mphash/NodeClass.cpp:36: multiple definition of `NodeClass::NodeClass(std::vector<std::string*, std::allocator<std::string*> >&)'
build/Debug/Cygwin64-Windows/NodeClass.o:/c/home/skidmarks/Projects/MPHASH/mphash/NodeClass.cpp:36: first defined here
Header file:
# include <vector>
# include <gslip/SlipPointer.h>
class NodeClass : public SlipPointer
{
private:
vector<string*> vec;
public:
NodeClass(vector<string*>& vec);
virtual ~NodeClass() { };
private:
NodeClass(const NodeClass& orig) { };
};
Source Code:
# include <vector>
# include "NodeClass.h"
using namespace std;
using namespace slip;
NodeClass::NodeClass(vector<string*>& vec) :
SlipPointer(new string("Cluster Node")), vec(vec) {}
You have not provided sufficient info to confidently identify your compile error. I agree it is possible that a double definition might happen without sufficient and appropriate include guards. You have shown no include guards, and your error is not evident in the above code,
There are 2 types of include guards. I have seen both used, but less often at the same time. All are examples of conditional compile commands.
In the header file with name "NodeClass.h", my version of the header guard would have the first 2 and last line (examples of conditional compilation) of the following:
#ifndef NODECLASS_H // <--- header include guard
#define NODECLASS_H // <---
#include <vector>
#include <gslip/SlipPointer.h>
class NodeClass : public SlipPointer
{
private:
vector<string*> vec;
public:
NodeClass(vector<string*>& vec);
virtual ~NodeClass() { };
private:
NodeClass(const NodeClass& orig) { };
};
#endif // <---
In the code file, name "NodeClass.cc", my 2nd version of the header guard would include similar conditional compilation statements. This is less used in most environments, and I prefer the above.
#ifndef NODECLASS_H
#include "NodeClass.h"
#endif
#include <vector> // <-- redundant since also in header
using namespace std;
using namespace slip;
NodeClass::NodeClass(vector<string*>& vec)
: SlipPointer(new string("Cluster Node"))
, vec(vec)
{
}
I suspect you have out-of-line definitions of these functions in you header.
Initialization list is part of constructor's definition so you need to define it at the same place you define constructor's body. This means that you should have to do it in your header file:
NodeClass(vector<string*>& vec) :
SlipPointer(new string("Cluster Node")), vec(vec) {}
Since the definition of the constructor is not inline in the class definition, the compiler does not make it implicitly inline. Now, if you include the same file in multiple translation units (i.e. *.cpp files), the linker will produce exactly the error you see, because each of the *.cpp files will contain its own definition of the constructor without them being marked as inline functions.
Alternate easy solution is just to put a inline in front of the constructor declaration:
public:
inline NodeClass(vector<string*>& vec);
I want to use extern keyword for user defined types. This means I've declared object in one file and defined it in other file. I've read that extern keyword is used to declare the variable without defining it. extern keyword is useful when program is split into multiple source files and global variable needs to be used by each of them. Please correct me If I am wrong somewhere.
Here is the programs I've written but unfortunately I am doing something wrong or missing something so I am getting compiler errors.
Prog1.cpp
#include <iostream>
using std::cout;
class test
{
public:
void fun();
};
void test::fun()
{
cout<<"fun() in test\n";
}
test t;
Prog2.cpp
#include <iostream>
using std::cout;
extern test t;
int main()
{
t.fun();
}
Now when I compile these 2 using
g++ -o prog1.cpp prog2.cpp
compiler gives me following errors in prog2.cpp
error: 'test' does not name a type
error: 't' was not declared in this scope
Please help me to know what I've done wrong here.
extern tells the compiler that the definition of t is somewhere else, but the compiler still needs the defintiion of test, as you're using t.fun() to compile Prog2.cpp.
So the solution is, write test.h where you define the class, and then define test t in Prog2.cpp as usual. Include test.h in your Prog2.cpp so that it may know the definition of test. Then build it.
test.h:
#include <iostream>
using std::cout;
class test //definition of test
{
public:
void fun()
{
cout<<"fun() in test\n";
}
};
Prog1.cpp:
#include "test.h"
test t; //definition of t
Prog2.cpp:
#include <iostream>
#include "test.h"
using std::cout;
extern test t; //the definition of t is somewhere else (in some .o)
//and the definition of test is in test.h
int main()
{
t.fun();
}
Now your code should compile and link.
Note that the definition of t is needed by the linker at link-time, so it will search for it in other .o files, but the definition of test is needed by the compiler, at compile-time.
Now it should be obvious that you can put the extern test t; in the header itself so that you dont have to write it in every .cpp file where you want to use the object defined in Prog1.cpp file (which is turned into Prog1.o by the compiler).
Put the extern keyword in the header, not the cpp file. It is the job of the header to tell the compiler there is an externally defined object somewhere.
For example:
program.h (mostly declarations)
struct UserDefinedType
{
void do_stuff();
};
// declare your global object in the header
// so that the compiler knows its name when
// compiling sources that can not otherwise see
// the object
extern UserDefinedType global_udt;
program.cpp (mostly definitions)
#include "program.h"
// define the member functions here
void UserDefinedType::do_stuff()
{
}
// define the global object here
UserDefinedType global_udt;
main.cpp (use the definitions that have been declared in the header)
#include "program.h" // tells the compiler about global_udt
int main()
{
// call the global object that is defined
// in a different source file (program.cpp)
global_udt.do_stuff();
}
NOTE: If we didn't declare the object global_udt in the header file then main.cpp would not know of its existence and the compiler would complain if we tried to use it.
So the header needs to only declare the object and not define it hence the extern keyword is needed.
Please note that a variable declared outside the class scope is a variable with external linkage(if not explicitly used the static keyword) or with internal linkage(if the static keyword is put in the left of the variable type), extern is necessary if you want to use it in multiple files.
Suppose this file is called MyVariable.h
int myNumber = 0; // Initialization of the variable myNumber, external linkage
static int myStaticNumber; // Initialization of the variable myStaticNumber, internal linkage(only the file in which it's declared)
And this file is OtherFile.cpp
extern int myNumber; // Not a initialization because it's already initialized in another file, works fine
extern int myStaticNumber; // ERROR, this variable has internal linkage!!
You may wonder why myStaticNumber was initialized and not just declared, that occurs because static variables are initialized to their default values by default.
Consider the following code:
In header.h
#pragma once
class someClass
{
public:
void foo();
};
In header.cpp
#include "header.h"
inline void someClass::foo(){}
In main.cpp
#include <iostream>
#include "header.h"
using namespace std;
int main()
{
someClass obj;
obj.foo();
}
Here I get a link error because foo function is defined as inline in header.cpp, if I remove the 'inline' keyword, the compile and run will proceed without errors.
Please tell me why I get link error on this 'inline' function?
The way you wrote it, inline applies to the current file scope. When an inline function is in a header, that header is included in a cpp file, and then the function is inlined where it is used in that file's scope, so there is no problem. In this case, your function is available as inline only where it is defined, and no other cpp file sees it, except as a regular member declaration in its class, hence the link error.
If you want it to be inline, add the code and the inline keyword in the header.
I am trying to compile a minimal example which instantiates
a template class. The example compiles fine when a certain order
of declarations is kept, but fails otherwise.
temp.h:
#include <iostream>
template <bool display>
class test {
public:
void sayHi();
};
temp.cpp:
#include "temp.h"
template <bool display>
void test<display>::sayHi () {
if (display) std::cout << "Hi";
}
main.cpp:
#include <iostream>
#include "temp.h"
int main () {
test<true> myobject;
myobject.sayHi();
return 0;
}
This is the standard of how to include classes.
In GCC 4.4.6, this fails with the error
main.cpp:(.text+0x3a): undefined reference to `test::sayHi()'
However, the example compiles when I do a #include "temp.cpp" instead of #include "temp.h" in main.cpp
file, so that the compiler reads the class declaration in temp.h first, then
sees the content of temp.cpp and only afterwards the content of main.cpp.
When I use non-template classes, it works fine to include just .h files
in main.cpp -- what is going wrong here? Note that the temp.cpp is included
in my Makefile, so it definitely should not be forgotten by the compiler.
Thanks for any help.
See the C++ FAQ Lite entry [35.12] Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?.
The definition (aka body) of the sayHi() method must be in the temp.h header, or in another included file; the full code is needed when you instantiate test<true>.
With templates, both declaration and definition must be in the same file. You can do this by either putting all your code in one file (and making the function definitions inline or not, it's up to you), or making the declaration and definitions seperate, but including the definitions file at the bottom of the .h file.
So it would be
tmp.h:
#include <iostream>
template <bool display>
class test {
public:
void sayHi();
};
#include "tmp.cpp"
and tmp.cpp and main.cpp remain the same (but you don't give tmp.cpp to the compiler to compile since it's included by tmp.h).
Many people name the files that have template function definitions in them with a .template extension instead of .cpp extension (it lets you know it's not to be compiled, plus it looks less weird than including a .cpp file), but you don't have to.