Undefined Reference To Member function - c++

I'm trying to solve a compiling problem regarding outside defined constructor.
Here's 2 of the classes that have this problem:
//Username.h
#ifndef USERNAME_H
#define USERNAME_H
#include <string>
using namespace std;
class Username{
private:
string Name;
public:
Username(string = "");
string getName() const;
void setName(string);
};
#endif
...
//Username.cpp
#include "Username.h"
Username::Username(string n):Name(n){}
string Username::getName() const{return Name;}
void Username::setName(string n){Name = n;}
...
//User.h
#ifndef USER_H
#define USER_H
#include <string>
#include "Username.h"
using namespace std;
class User{
protected:
Username* UserUsername;
public:
User(string s);
virtual ~User();
Username* getUsername() const;
void setUsername(Username*);
};
#endif
...
//User.cpp
#include "User.h"
User::User(string s):UserUsername(new Username(s)){}
User::~User(){}
Username* User::getUsername() const{return UserUsername;}
void User::setUsername(Username* u){UserUsername=u;}
int main(){return 0;}
If I compile using "g++ User.cpp" I get this error:
/tmp/ccEmWmfl.o: In function `User::User(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)':
User.cpp:(.text+0x3e): undefined reference to `Username::Username(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
collect2: ld returned 1 exit status
If I use "g++ User.cpp Username.cpp -o main" or if I use inline constructors/destructors I get no error.
These classes are very easy, but I have tons more to compile that require more than one class.
I'm new at compiling in Ubuntu shell with g++, so please, can someone help me to understand?

g++ User.cpp
This compiles User.cpp and attempts to create an executable from it (ie the linker is invoked). Since User.cpp has a symbol not fully defined in User.cpp (the Username constructor here:
User::User(string s):UserUsername(new Username(s)){}
the symbol is expected to be defined at the link stage. Linking is done by combining all the generated object file output of all the cpps you generated and piecing together the missing symbols. Here you're not telling g++ about where to find the full definition of the Username constructor other than the cpp with main, so its failing.
This, however:
g++ User.cpp Username.cpp -o main
Tells the linker where to find full Username definitions (in the object file generated by compiling Username.cpp). So linking can succeed in filling in the missing pieces by using whats defined in Username.cpp to match up identifiers not defined in User.cpp.
You may think -- "well I've told the compiler about it by including the header file, it should know!". What you've done is declared the symbol. You've made a promise that something will eventually be defined, either during compilation of that one cpp or by later linking it with another object file generated by compiling another cpp. g++ needs to know where you intend to pull all your definitions from so it can build a final executable correctly.

You already answered your question, if you don't add Username.cpp at the compilation process User can't knwo it.

You can use partial compilation, with the -c flag:
g++ -c User.cpp
This produces a User.o file.
You do this partial compilation thing on each of your files
g++ -c Username.cpp
And then you link all the object files (the *.o files) together:
g++ User.o Username.o -o main
Usually, you'd use some build system to automate this process. With that you'd also get other advantages, like not skipping the recompilation of files that didn't change since the last compilation.

This can also happen, if you are trying to call a member function of a template class from the source file other than the implementation file of the template class. For example: you have clas ABC with ABC.h and ABC.cpp (implementation file).
As long as your calls to generic objects lies in ABC.cpp, all works well. However, if you try to include ABC.h in another class say BCD and call any member function of object ABC, you will get the Undefined Reference To Member function error.
Solution: Create a single header file for your template classes including the implementation to avoid this error which is misleading.

User.cpp add:
#include "Username.h"

It's not really a C++ problem, but more a GCC issue. Normally, you'd build a larger program with Make. You then have a makefile rule that builds all .cpp files in a directory and links hem together. An alternative is that your makefile specifically states which .cpp files should be compiled together.

You have to pass all of your implementation files to the g++ executable. The first compilation attempt fails because you're only compiling User.cpp into an object file and linking it into an executable object called main.
In the second attempt you correctly pass both necessary implementation files to the g++ executable. In this case, User.cpp and Username.cpp are compiled into object files and linked together to form the main executable. In this case, the implementation of the Username::Username() constructor is present.

Related

VSCode Makefile no longer creating executable, which fails when make is invoked

So I was practicing with a tutorial series on C++ projects for Linux. In order to create the makefile I did CTR+SHIFT+P to go into Palet, searched for make file, selected the correct option, and selected C++ project. In the tutorial, the person changed src in the make file to a static path ie: pwd. That worked. When he changed back to src and after moving the files into the src folder like he did, doing make clean, and then make, I get this:
[termg#term-ms7c02 HelloWorldnonVR]$ make
g++ -std=c++11 -Wall -o obj/list.o -c src/list.cpp
g++ -std=c++11 -Wall -o obj/main.o -c src/main.cpp
g++ -std=c++11 -Wall -o HelloWorld obj/list.o obj/main.o
/usr/bin/ld: obj/main.o: in function `List::List()':
main.cpp:(.text+0x0): multiple definition of `List::List()'; obj/list.o:list.cpp:(.text+0x0): first defined here
/usr/bin/ld: obj/main.o: in function `List::List()':
main.cpp:(.text+0x0): multiple definition of `List::List()'; obj/list.o:list.cpp:(.text+0x0): first defined here
/usr/bin/ld: obj/main.o: in function `List::~List()':
main.cpp:(.text+0x2c): multiple definition of `List::~List()'; obj/list.o:list.cpp:(.text+0x2c): first defined here
/usr/bin/ld: obj/main.o: in function `List::~List()':
main.cpp:(.text+0x2c): multiple definition of `List::~List()'; obj/list.o:list.cpp:(.text+0x2c): first defined here
collect2: error: ld returned 1 exit status
make: *** [Makefile:37: HelloWorld] Error 1
[termg#term-ms7c02 HelloWorldnonVR]$
There are three files. A class and its header, and then the main. list.h is in the include subfolder for src.
I currently cannot find any information about this problem, so any help would be appreciated. The tutorial had no issues with making or running the files. The VSCode extension is C/C++ Makefile Project. My system is Manjaro. I did do make clean and delete the makefile to start fresh, in case I hit the keyboard or something but same result persists. From what I am seeing, the issue is that there is no HelloWorld executable being created. HelloWorld is the appname in the template.
Narrowed the issue down to the header. Without constructors it works but with them it does not.
#include <iostream>
#include <vector>
using namespace std;
class List
{
private:
/* data */
protected:
public:
void print_menu(); //Prototype
void print_list();
void add_item();
void delete_item();
vector<string> list;
string name;
//constructor
List(/* args */);
//destructor
~List();
};
List::List(/* args */)
{
}
List::~List()
{
}
Any ideas on what is causing this?
The error message tells you exactly what the problem is, if you learn the compiler-ese to interpret it:
main.cpp:...: multiple definition of `List::List()'; obj/list.o:list.cpp:...: first defined here
Here it's saying you have defined the constructor twice: once in main.cpp and once in list.cpp.
And, as is the case 99.99999% of the time, the compiler (well in this case technically the linker) is correct. You have defined the constructor and destructor in the header file, and you've included the header file in both the main.cpp file and in the list.cpp file, so the constructor and destructor are defined in both, just as the error says.
You need to put the constructor and destructor in the list.cpp source file, not in the header file.
Alternatively you can put them inside the class itself, which makes them inline, and then you won't have this issue:
class List
{
private:
/* data */
protected:
public:
List(/* args */) {}
~List() {}
void print_menu(); //Prototype
Of course this only makes sense if they are small and simple enough to inline like this.

No multiple definition error despite including source file in another and compiling both

Let's say I have 3 files:
Test.hh
#ifndef TEST_HH_
#define TEST_HH_
class Test
{
int test() const;
};
#endif /* TEST_HH_ */
Test.cc:
#include "Test.hh"
int Test::test() const
{
return 0;
}
main.cc:
#include "Test.cc"
int main()
{
return 0;
}
It does not compile (rather does not link), I understand why, I defined Test::test() in multiple translation units (in main.cc that includes Test.cc and in Test.cc):
g++ -Wall -g -std=c++17 -c main.cc -o main.o
g++ -Wall -g -std=c++17 -c Test.cc -o Test.o
g++ -o bin main.o Test.o
Test.o: In function `Test::test()':
Test.cc:12: multiple definition of `Test::test()'
main.o:Test.cc:12: first defined here
collect2: error: ld returned 1 exit status
Edit: This is NOT my issue, my issue is that with a seemingly identical situation, in a bigger project, the previous example produces a binary (i.e. compiles and links) when, as far as I understand it, it shouldn't. I will now describe the real case with a bit more details and how the problem suddenly arised when previously it was working fine (when it shouldn't have).
--
I am currently working on a large project (~2500 files), and while trying to use the "Test" class above, I ended up having a lot of "multiple definitions" errors at link time. To translate it to our example, it's like I had another class doing this:
OtherClass.hh
#include "Test.hh" // including or using forward declaration led to the same results
//class Test; forward declaration
class OtherClass
{
// Some stuff, whatever
};
I ended up finding that Test.cc was included in another source file (main.cc in my very simplified exemple though it was in another "someClass.cc" in my actual project). After including the header instead of the source, it compiled again. What's more surprising is that other classes had been using Test.hh the same way until then without any problems.
Since I was really surprised, I ended up doing a grep on all my files and found that another 2 source files had included other sources files as well.
WhateverClass.cc
#include "Test2.cc"
YetAnotherClass.cc
#include "Test3.cc"
All those files are compiled and contain function definitions yet the linker does not complain. I tried doing a compilation from scratch and it still worked.
So my question is: Why does this compile even though some source files include others and all of them are compiled ? And why did it suddenly stop working even though I just included the header of one of those source files just like other classes had been doing ? Is there a kind of "undefined behavior" for cases like this ?
If it is of any help, my project is using CMake. I tried compiling with ninja or Make with the same results.
I had a similar question before. So, here's what I learned- never include source file. Only include header files. Your error comes from including a source (.cc) file in your main. You should include Test.hh instead. Declare all your classes and functions in header, include that header to all the source files where the definitions and the calls are.

Makefile not working when changing function argument to const

I have a strange problem when compiling a C++ code using a makefile. The code first compiles perfectly. Then I change one function argument to "const". If I then compile, I will receive the error message when the code tries to use the function in which I changed the argument to const. This can be resolved by removing all .o files and then compiling again, but I am curious as to what causes this issue in the first place. My files are:
MyClass.h
class MyClass {
public:
void fun(double*const c);
};
MyClass.cpp
#include "MyClass.h"
void MyClass::fun(double *const c){
};
Main.cpp
#include "MyClass.h"
int main(int argc,char* argv[]) {
MyClass foo;
double *bar=new double[2];
foo.fun(bar);
};
Makefile
all: main
main: Main.o MyClass.o
g++ -o a.out Main.o MyClass.o
Main.o: Main.cpp
g++ -c Main.cpp
MyClass.o: MyClass.cpp
g++ -c MyClass.cpp
If I now first run make, everything works. But then I change the signature of fun to fun(const double *const c), I receive the error message
Main.cpp:(.text+0x3b): undefined reference to `MyClass::fun(double*)'
collect2: error: ld returned 1 exit status
Makefile:6: recipe for target 'main' failed
make: *** [main] Error 1
However, if I remove all the .o files and then run make again, it compiles.
The rule
main.o: Main.cpp
says thay the main.o object file only depend on the Main.cpp source file. But it actually depends on another file: The MyClass.h header file.
There's also an error in the capitalization of the name of the target.
The above two problems means that when you change the header file MyClass.h to update the function signature, the Main.o object file will not be recreated and still reference the old function.
So the rule should be
Main.o: Main.cpp MyClass.h
That addition will cause the Main.o object file to be recompiled when you change the header file.
This change should also be done for the MyClass.o target.
Also note that the main target uses MyClass.o as a dependency, but then you use the MyClass.cpp source file when linking, instead of the object file.
The name of the target should also be the name of the generated file (i.e. a.out in your case).
The problem is, that your Makefile is broken: It ignores the fact that a .o file does not only depend on the corresponding .cpp file, but also on the .h files it includes. A correct Makefile rule must include all dependencies, including the directly, or even indirectly included .h files.
Since you Makefile is incomplete, make did not recompile the calling site of your function when its definition changed, so the stale object still references the non-const function. Due to C++ name-mangling, the linker caught it in the act, the error would have gone unnoticed in C!
To fix this situation for good, I recommend spending an hour or two reading this article on automatic dependency generation, and implementing some of the solutions it offers into your Makefile. Once you have done this, you will likely just copy-cat your existing solution into the Makefiles of future projects, and otherwise forget about the problem.

Confusion between including header files and source files in main program

I have heard that we should write the declarations in a header file and the definition in a source file, with both the source and the header having the same name. And then just include the header in the source.
Here is an example myFile.h:
void printer (void);
Here is the implementation of printer in myFile.cpp:
#include "myFile.h"
#include <iostream>
using namespace std;
void printer ()
{
cout<< "I am a printer";
}
Here is my main.cpp:
#include "myFile.h"
int main ()
{
printer();
return 0;
}
Now when I run the program, I get the expected error: undefined reference to printer. But when I see code on github or other projects I see that usually they have included the header file and not the source file. I also tried using the header guards ifndef but still the same error came.
The main program is successfully compiled if:
If i include myFIle.cpp in myFile.h
If i include just myFile.cpp in main
What I the general practice while doing the same?
You should include your myFile.cpp in the linking process:
g++ myFile.cpp main.cpp
The error message undefined reference to printer is actual a linker error, not a compiler error.
Explanation
If you use only g++ main.cpp compiler won't create code from myFile.cpp. He knows that there should be a function with the signature void printer(void), but he doesn't now yet where this function is. He completely ignores this fact, since you can provide pre-compiled object files ("myFile.o") and link those later:
g++ myFile.cpp -c # compile myFile.cpp
g++ main.cpp -c # compile myFile.cpp
g++ myFile.o main.o # link both files together.
-c will tell g++ only to compile the files, but not link them together to an executable. This is done by a linker (g++ will probably call ld in your configuration). The linker will create an executable which contains all needed libraries like libc++ and actual code.
IDE remarks
If you use an IDE make sure that all needed files are included in the project. This includes all header and source files and linkage options for additional libraries.
When yourself define a header file and want to include it, you should enclose it "", such as :
#include "myFile.h"
#include "myFile.h" // would be better.
It seems you forgot the " surrounding the include.
You should use
#include "myFile.h"
or
#include <myFile.h>
the later is rather for system libraries. Both forms differ in the way the search the file.
You find more details on
http://msdn.microsoft.com/en-us/library/36k2cdd4%28v=vs.71%29.aspx

c++ undefined reference to <a function>

HI,
I have some questions about .h files and .cpp files in c++/linux(ubuntu).
It is possible to compile a .h file using g++ or you can just compile a .cpp file that includes the .h file?
From a .h file and it's .cpp file (.cpp where i include some code to the methods i've defines in .h file) I create a .so file using the command:
g++-fPIC -shared my_code.cpp -o my_code.so`
In the test.cpp I include the .h file and using dlopen i create a handler over the .so file. Why do I have the following error:
undefined reference to bool `Class::method(std::string)` `collect2: ld returned 1 exit status
If I say virtual bool method... in the .h file there is no error when I compile test.cpp. Can someone explain what am I doing wrong? The thing is that i have a template. With templates I cannot use virtual..so..i have this undefined error and i don't know how to resolve it. THX
EDIT:
When i compile the my_code.cpp I have the errors:
/usr/bin/ld: .usr/lib/debug/usr/lib/crt1.o relocation 0 has invalid symbol index 12 (same with index 13,2,14...22 ).
But when i create the .so file there is no error . I use:
g++ test.coo -ldl -o test
for the test.cpp compilation.
Ad 1: It is possible to compile .h file (you can explicitly override the language detection), but you don't want to do it. The .h file is intended to be included and will not compile to anything useful on it's own.
Ad 2: You have to link against the library you created by passing the -lmy_code (but note that for that to work you have to create it as libmy_code.so) along with appropriate -L flag (directory where you placed libmy_code.so) to the linker. Like this:
g++ test.cpp -L. -lmy_code -ldl -o test
But you also have to change the first command to:
g++ -fPIC -shared my_code.cpp -o libmy_code.so
^^^
libraries *must* have `lib` prefix on unix systems.
and this assumes both are done in the same directory—if not, you have to adjust the -L option to point to the directory where libmy_code.so is. Also you have to place libmy_code.so somewhere where the dynamic linker can find it. Either by installing it or by setting environment variable LD_LIBRARY_PATH to appropriate directory. Alternatively you can compile by using
g++ test.cpp my_code.so -ldl -o test
This does not force the lib prefix and it creates an "rpath" entry in the binary so it will find the library in the original place.
This all assumes you want to use it as regular library in which case you don't want to use dlopen. dlopen is for opening libraries as plugins at runtime and than they can only be accessed by fetching pointers to symbols using dlsym(), but if you want to access the library normally, you have to link against it so the linker can resolve the symbols.
If instead you wanted to use dlopen, you must not include my_code.h in test.cpp and must not use anything it defines except by getting the symbols with dlsym. And since this is C++, it in turn requires you understand the symbol mangling scheme, because dlsym will not do this for you.
Generally there is no need to compiling a .h file, it simply generates a huge file with .gch extension I guess.
The error you are getting is a link time. While creating the .so file, you do not actually link the code. So all undefined symbol are assumed to be present at some place. When you link it, the linker will find for those symbols. So, you should compile/link all the .cpp file together. The error will go away.
Also, For templates, the definition of the code must always be visible. So wherever you write the templated function/variable definition, include that file everywhere.
Edit:
You can have virtual method with template classes; but you can not have virtual template methods.
template<typename T>
class A {
virtual void foo(int); // ok
};
class A {
template<typename T>
virtual void foo(T); // illegal
};