Okay, so this is really werid. I've never encountered anything like this.
Part of my program (Fails to compile) contains three namespaces as following:
// namespaceA.h
namespace A {
enum Kind { jimmy, david };
}
// end of namespaceA.h
// namespaceB.h
#include "namespaceA.h"
namespace B {
class Tree {
public:
Tree *prev;
Tree *next;
Tree *down;
A::Kind kind;
Tree();
~Tree();
};
}
// end of namespaceB.h
// Implementation details of the class are placed in namespaceB.cc
// Constructor / Desctructor defined in the namespaceB.cc file!
// Something like this,
#include "namespaceB.h"
namespace B {
inline Tree::Tree() { ... }
inline Tree::~Tree() { ... }
}
// namespaceC.cc
#include "namespace.B"
namespace C {
void run() {
B::Tree *tree; // FINE
B::Tree tree; // Fail to compile!?
}
}
// end of namespaceC.cc
Now, g++ went along just fine but the linker ld complains:
"namespaceC.cc: undefined reference to `B::Tree::Tree()'
"namespaceC.cc: undefined reference to `B::Tree::~Tree()'
I have never ever encountered anything like this before... This just seems really weird, I don't even know any words/terms to describe this problem.
I would much appreciate any help.
Thanks,
namespaceC.cc: undefined reference to `B::Tree::Tree()'
namespaceC.cc: undefined reference to `B::Tree::~Tree()'
Those are not compiler errors, they are linker errors. The problem is that you declared the constructor and destructor, but never defined them. So the compiler finds the declarations and accepts them, but the linker cannot find the definitions to link the references to.
See this answer for what is a declaration and what is a definition and what they are good/needed for.
Your definitions of B::Tree::Tree() and B::Tree::~Tree() are declared inline. This means they are only available in that source file, not any others.
Either removing inline from the definitions, or moving the inline definitions into a header file included by all source files that need them, should fix the link errors.
You have to write the constructor and destructor for B::Tree somewhere either inline or in namespaceB.cc. By creating an instance of B, you are requiring the existence of the constructor and destructor.
The pointer compiles fine because all pointers are the same. It's just the semantics allowed for different object types differ.
It would have compiled find up until the point you tried to use it.
But to create an actual object, you need the actual definition.
To use definitions from another namespace, you either used scopes, or use using:
#include "namespace.B"
using namespace B;
namespace C {
void run() {
Tree *tree; // FINE
Tree tree; // Fail to compile!?
}
}
or:
#include "namespace.B"
namespace C {
void run() {
B::Tree *tree; // FINE
B::Tree tree; // Fail to compile!?
}
}
You declare the Tree constructor & destructor, but you don't show us where you define them (you just say you implement Tree in namespaceB.cc)
Assuming you have defined them, you must ensure you are including both namespaceC.o and namespaceB.o on your link line.
That's not a namespace problem, neither a compiler error. The compiler is happy, but linker fails to find the definition of B::Tree::Tree(). You need to supply the source file for implementation, or use -c flag to "just compile".
First, you declared constructor and destructor of class Tree yourself so compiler didn't provide default implementation - you need to implement them yourself! (Or just remove those declarations...).
It is not enough to include headers but you need to explicitly say that you're using namespaces from those headers:
In namespaceC.cc add using namespace B; after you include namespace.B or, even better, prepend types with a namespace qualifier:
B::Tree *tree;
B::Tree tree;
I tried the codes in Visual studio 2005. If I remove the "inline" in namespaceB.cc for the constructor and destructor, it can link without errors.
Then I found this post: G++ won't accept inline constructors in C++
it says that for inline functions you must have its definition in every file that calls the function. So it is recommended to put inline definition in header file.
Related
I'm defining a class SpatialCriterionCallback in a header file "spatialcriterion.h" like this:
#include "ros/ros.h"
#include "neuromorphic_stereo/MatchingCandidates.h"
#include <vector>
class SpatialCriterionCallback
{
public:
// constructors & destructors
SpatialCriterionCallback()=default;
SpatialCriterionCallback(ros::NodeHandle);
~SpatialCriterionCallback()=default;
private:
std::vector<neuromorphic_stereo::MatchingCandidates> matching_candidates;
void subscriberCallbackFunction(constneuromorphic_stereo::MatchingCandidates&);
}
Then in the file "spatialcriterion.cpp" I'm defining a constructor that invokes a ros::SubscriberNode like this:
#include "spatialcriterioncallback.h"
SpatialCriterionCallback::SpatialCriterionCallback(ros::NodeHandle n)
{
this->n =n;
this->time_criterion_topic_handle = this->n.subscribe("TimeCriterionTopic",
1e4,
&SpatialCriterionCallback::subscriberCallbackFunction,
this);
}
When I try compiling this within a qtcreator project, the compiler tells me
error: undefined reference to
`SpatialCriterionCallback::subscriberCallbackFunction(neuromorphic_stereo::MatchingCandidates_ const&)'
When I add the following lines to my "spatialcriterion.cpp" file it will compile just fine:
void SpatialCriterionCallback::subscriberCallbackFunction(const neuromorphic_stereo::MatchingCandidates & msg){
this->matching_candidates.push_back(msg);
}
Now my question is: Shouldn't this code compile without the function definition, because the function subscriberCallbackFunction() has already been declared in "spatialcriterion.h"? Why is it necessary for the compiler to have the function defined?
I also tried finding an explanation to this behaviour here, but all the other posts about failing forward declaration (like this or this) aren't exactly what I'm looking for.
Even if you declared the method in your class, it doesn't exist.
When you reference that function in the constructor, the linker tells you that it needs to know where the method is.
The code compiles fine, it doesn't link.
namespace n1 {
namespace n2 {
...
int myfunc(void)
{
return 1;
}
class myclass {
..
};
}
}
I thought it is possible to define a function this way, and access it both from 'myclass' and its derivatives. However gcc doesn't even want to compile this code:
multiple definition of `n1::n2::myfunc()'
This function is the only one here, what am I missing?
Thanks.
You need to either mark the function inline to avoid breaking the one definition rule, or place the implementation in a .cpp file, and leave only the declaration in the header.
consider a fun.cpp file :
class fun
{
public:
void sum();
void dispaly();
};
Class fun2
{
public:
void subtract();
};
Now consider another c++ file execute.cpp where i want to access only subtract method of fun.cpp file..
i dont want to include "fun.cpp" file into my execute.cpp as it will increase the size(in larger projects)..
so, how can i access any particular method wihtod including the file????
i dont want to include "fun.cpp" file into my execute.cpp
Nor should you, as it would break the one definition rule (assuming the implementations are also in the cpp file).
The usual way to do this is to have the class definition in a header, and include only the header file.
To answer your question, you can, but it's fugly.
C++ allows us to define a class multiple times, as long as the definition is identical. So, in execute.cpp you can simply write:
//execute.cpp
class fun2 //note lower-case 'c'
{
public:
void subtract();
};
// use fun2 here
before you use it. But, again, the usual way is to break the class definition and implementation in a .h file and a .cpp file.
Mandatory advice: read a good introductory C++ book.
You need to include the header file which defines the class fun(and has the declaration of subtract()) in the cpp file where you want to use the function subtract().
Note that the function must be defined though.
fun2.h
#ifndef FUN2_H
#define FUN2_H
Class fun2
{
public:
void subtract();
};
#endif // FUN2_H
fun2.cpp
#include "fun2.h"
void func2::subtract()
{
}
execute.cpp
#include "fun2.h"
//use subtract() through object of `fun2`
Note that, to use a member function in a particular source file, the definition of the class which declares that function should be visible to the compiler, the actual job of linking to the particular definition is done at the linking stage and as long as you follow the above format the linker shall link the appropriate function for you.
Even though you include the file, the linker will only include code that is actually used. This is why using static libraries is sometimes preferable to a dynamic library that has to include everything.
You can't. You need to actually include the file that links to the code that defines the function if you want to include the function. If you just need the interface and aren't going to use the function, you could simply declare the class in execute.cpp as follows
class fun
{
public:
void subtract();
};
But you couldn't use subtract there.
I'm trying to declare an object from a class in another file. I have added the #include "transfer.h" into my metadata.cpp file, but I'm getting the following error:
metadata.o: In function `importMetadata':
metadata.cpp:(.text+0x81): undefined reference to A::B::C::Transfer::Transfer()'
metadata.cpp:(.text+0x81): undefined reference to A::B::C::Transfer::~Transfer()'
And Transfer is defined with in transfer.h
namespace A{
namespace B{
namespace C{
class Transfer {
public:
Transfer();
~Transfer();
int copydata();
... more code goes here.
};
}
}
}
The file transfer.cpp looks like this:
Transfer::Transfer(){
}
Transfer::~Transfer(){
}
I'm also doing an using namespace A::B::C; on the header of the metadata.cpp file. Could someone please help me on that?
In the function int importMetadata() in metadata.cpp I'm declaring Transfer transfer; so in metadata.cpp I'm doing 'transfer.copydata();`
Since you have linker error and not a compiler error this tells you that your #include statement is doing what you want and the compiler recognizes the Transfer class and its constructor. The error occurs when the linker tries to find a reference to the implementation of the Transfer::Transfer() function in one of the .o or .lib files its told to link but cannot find it.
It's likely you have a transfer.cpp to go along with the transfer.h and this file is missing the implementation of the Transfer constructor and destructor. This could be because the functions are missing altogether or have been accidentally defined with a different signature.
So transfer.cpp should look something like:
A::B::C::Transfer::Transfer()
{
}
A::B::C::Transfer::~Transfer()
{
}
Another possibility is that you are trying to link the implementaiton of transfer from a library. In this case you would need to tell your linker to use the .lib file as input. The syntax for this will depend on the compiler you are using.
Hopefully you left out part of your transfer.cpp file, but in case you didnt it should define the namespace to match your header file like such:
namespace A{
namespace B{
namespace C{
Transfer::Transfer(){
}
Transfer::~Transfer(){
}
}
}
}
In case you have fully defined the namespaces, either inline or as above, you'll want to make sure you have the transfer.cpp file included in your project. Seems like the linker is unable to find your source file.
Say I have something the following in my program,
// namespaceB.h
#include "namespaceA.h"
namespace B {
class Tree {
public:
Tree *prev;
Tree *next;
Tree *down;
A::Kind kind;
Tree();
~Tree();
};
}
// end of namespaceB.h
// Implementation details of the class are placed in namespaceB.cc
// Constructor / Desctructor defined in the namespaceB.cc file!
// Something like this,
#include "namespaceB.h"
namespace B {
inline Tree::Tree() { ... }
inline Tree::~Tree() { ... }
}
My question is that does inlining the ctor/dtor restrict their uses to within the current source file?
I thought inlining is just a way to improve efficiency?
What if Tree has a memeber method like
Tree& Tree::operator+(Tree const& rhs);
defined in header file, and in the source file
inline Tree& Tree::operator+(Tree const& rhs) { ... }
I played with that a bit, and it seems "inline" here also restricts Tree::operator+(...) to the scope of that source file
which means this will fail:
#include "namespaceB.h"
int main() {
B::Tree tree; // Fail to link
return 0;
}
As shown here:
Cannot create an instance of a class from another namespace?
After I removed "inline" from ctor/dtor of class Tree, everything compiled and linked perfectly.
Can someone please explain what exactly inline does?
Thanks,
If you mark a function as inline, you must include it in every source file from which it is used.
The C++11 standard has this to say:
7.1.2/4: "An inline function shall be defined in every
translation unit in which it is odr-used and shall have exactly the
same definition in every case."