Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I wrote some code trying to understand the relationship between compiling and linking - and also to see where and if function declarations have to be repeated in source files.
The two files I wrote are:
Person.cpp:
#include <string>
class Person {
public:
Person(std::string name) {
(*this).name = name;
};
std::string getName() {
return name;
};
std::string name;
};
and the file
PersonMain.cpp:
#include <iostream>
class Person {
public:
Person(std::string);
std::string getName();
std::string name;
};
int main(){
Person* charlie = new Person("Charlie");
std::cout << "Hi, my name is " << charlie->getName();
}
I repeat the Class Person and Class Person function declarations (not the definitions) in the PersonMain.cpp.
I now compile and link the two files using the gcc C++ Compiler:
g++ *.cpp -o runthis.exe
I then get the following error message:
PersonMain.cpp:(.text+0xfe): undefined reference to
Person::Person(std::basic_string<char,
std::char_traits<char>,std::allocator<char> >)'
PersonMain.cpp:(.text+0x13c): undefined reference to
Person::getName()' collect2.exe: error: ld returned 1 exit status
It seems the Person Class methods are not found when linking. Why is that? How can I heal this?
ADDENDUM:
I repeated the declaration of Person in PersonMain.cpp explicitly, and didn't but the redeclaration into a header file as would be done normally. So I've done the preprocessor step here already. This faq suggests that:
[The Preprocessor] works on one C++ source file at a time by replacing
include directives with the content of the respective files (which is usually just declarations)[...]
and later on:
[The Linker] links all the object files by replacing the references to
undefined symbols with the correct addresses. Each of these symbols
can be defined in other object files or in libraries.
I add this remark becaue #engf-010 said that a Compilation Unit that has code that isn't actually used in that compilation unit is not compiled, even if it is needed in other compilation units. enf-010 suggests that I put the definition and declaration into the header file, but the faq article says that only the declarations should go there, the definitions can be elsewhere.
Usually one splits declarations and definitions into .h and .cpp files respectively.
Your code would look something like this:
person.h - declarations:
#include <string>
class Person {
public:
Person(std::string n);
std::string getName() const;
std::string name;
};
person.cpp - implementation:
#include <string>
#include "person.h"
Person::Person(const char* n) : name(n) { }
std::string Person::getName () const { return name; }
and personmain.cpp - where you use your class Person:
#include <iostream>
#include "person.h"
int main()
{
Person* charlie = new Person("Charlie");
std::cout << "Hi, my name is " << charlie->getName ();
}
Like #engf mentioned, essentially, what you got in your code is double definition of Person and no implementation. You can't easily define Person in main file and implement Person::Person() somewhere else (and you should not), in another translation unit (i.e., in person.cpp), without letting the compiler know what you implement. You can't forward-declare Person and use it in personmain.cpp like this:
class Person;
...
Person* charlie = new Person("whatever");
because compiler should know complete type to emit code constructing the Person-object. You can't have two definitions of Person. You can't implement members of Person without definitions, accessible to all users of your code. So, what you left with is the scheme like this above.
To elaborate a bit more on compilation and linking, very roughly, when compiler sees a reference to symbol not defined locally in the same translation unit, it puts appropriate record into object file. When this object file is passed to the linker (possibly, along with a bunch of other object files and libraries), linker should resolve such records to symbols (functions, variables etc.) found somewhere in input object files or libraries. If it succeeds in that, it combines all the referenced code into single image. In your case the linker failed to resolve referenced symbol Person::Person for constructor. Probably this is not bad Q&A to start.
what you've got is a definition in one source file and a declaration in the other source file.
When the source file containing the definition is compiled ,the compiler comes to the conclusion that there isn't any 'real' code to generate ,because you didn't use the class.
So you end up with an empty object file.
You can define a class in a source file but if you don't use that class in that file it is tossed away as not being used.
If you use that class in other source files (through it's declaration) the compiler generates code for member accesses ,but those are not found during linking.
Related
I want to Use one globe variable in all cpp files.If one class of the cpp file changed the value,I want to access it from another class cpp file,which is the value that least modified by any other cpp class file.
str.h - global variable file
#ifndef MY_PROG
#define MY_PROG
extern char * myname;
#endif
class1.cpp
#include "str.h"
char * myname;
class class1
{
class1(){}
~class1(){}
void Setname1(char *name) { myname = name }
};
class2.cpp
#include "str.h"
char * myname;
class class2
{
class2(){}
~class2(){}
void setName(char *name) { myname = name }
};
class3.cpp
#include "str.h"
class class3
{
class3(){}
~class3(){}
char *GetData()
{
return myname;
}
};
main.cpp
#include "str.h"
int main()
{
class1 c1;
class2 c2;
c1.Setname1("XXXX");
c2.setname("YYYY");
class3 c3;
cout << c3.GetData;
}
when I execute the program, I need to get Last modified value that is "YYYY" .I am new to cpp, And also please tell me whether I used the extern keyword correctly.If not , please provide me the right procedure.
The essential in your problem is understanding the difference between declarations and definitions of variables (and types, functions etc. objects in C/C++)
extern char * myname; is a declaration. It makes myname visible to other pieces of code in the same file so that they can reference it.
char * myname; is a definition. Not only it makes myname visible, it also instructs the compiler to allocate space for it and to make its address known.
You can have as many declarations of the same variable in your code as you want, as long as they do not contradict each other. No so with definitions. If you define a thing two times, it would need to be assigned two addresses, and then how can other object files "understand" which address to use when referencing it? The same goes with the space allocated — what to do with the extra piece of it allocated? This is the error that you see.
To make the code work, have only one and exactly one definition of myname in exactly one file. It must not be a header file because it gets copied into multiple source files thus creating multiple definitions. It can be any other C++ file though.
In the rest of the files (or in a single header included in all of them) have multiple declarations of myname if it is referenced in a particular file. If not, you can omit it for a particular unit.
All this being said, it is considered to be a VERY BAD PRACTICE to communicate data between compilation units through global mutable shared variables. They make code a nightmare to debug and understand and impossible to parallelize. Nobody ever thinking getting money for the code they write should use them. Instead, the best approach would be to pass a mutable object as one of methods/functions argument. Details actually depend on the rest of your application.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I've searched many answers but none of them can solve my problem, I'm new to c++, this issue is quite wired to me. Below is a simplified extraction of my code.
TestHeader.h:
#ifndef NAMESPACE_TESTHEADER_H_
#define NAMESPACE_TESTHEADER__H_
namespace Namespace {
class TestHeader {
public:
TestHeader(const std::string& str) : anyString_(str) { }
virtual std::string methodOne(const std::string& param) const;
virtual ~TestHeader() { anyString_.clear(); }
protected:
std::string anyString_;
};
}
#endif //NAMESPACE_TESTHEADER__H_
TestHeader.cpp:
#include "TestHeader.h"
using namespace std;
namespace Namespace {
TestHeader::TestHeader(const std::string& str):anyString_(str) { <do something>; }
std::string TestHeader::methodOne(const std::string& param) const
{
return <A string>;
}
TestHeader::~TestHeader() {
anyString_.clear();
}
}
What I did was simply call this line in any other .cpp in my package:
#include "TestHeader.h"
TestHeader testHeader("whatever");
The build failed by throwing
error: undefined reference to 'vtable for Namespace::TestHeader'
the vtable symbol may be undefined because the class is missing its key function
The most weird thing is: if I comment out virtual std::string methodOne(const std::string& str) const; in header and its implementation in .cpp, OR, if I comment out : anyString_(str) after constructor and anyString_.clear(); in destructor together in header only, the build will succeed.
Firstly You should not define the constructor and destructor twice. It shouldn't be compiling as mentioned by Curious in comments
Second I assume that you want don't the class to be abstract as there is no Runtime polymorphism implemented which is the basic use of Virtual functions.
If you don't want the class TestHeader to be abstract remove the virtual keyword which is referring to Virtual Table.C++ compiler inserts Virtual Table for every class having virtual function or class inherited from the class that has virtual functions.
Better study the use of Virtual keyword and then write the code.
Here are quick links for the same
Link 1
Link 2
Also, I think you need to revisit few concepts from Destructor virtual ~TestHeader() { anyString_.clear(); } does not make any sense. In fact, there is no base class which in turn denies the use of Virtual Destructor which is used in case of Inheritance
Firstly, include #include <string> at the top of your header file. I am guessing the error is because you have not linked the object file produced after compiling TestHeader.cpp with the source file that contains the declaration and initialization for the variable named testHeader
Compile these with the following command and you should see a linker error that complains saying that you have multiple definitions for the constructor
g++ -std=c++14 TestHeader.cpp yourfile.cpp
After you see those errors, remove the multiple definitions, either put all your definitions in the cpp file or only put them in one place and then recompile and link with the above command. The linker error should be gone.
I need help with figuring out how to code the given specifications since I'm really lost in how to use the three different source files and what needs to go in all of them.
#include <iostream>
#include<string>
using namespace std;
class Person
{
public:
Person();
string getName();
int getAge();
void setName(string newName);
void setAge(int newAge);
void display();
private:
string name;
int age;
};
This is all I have for Person.h so far.
Specification
1. Given Person.h
1(a). Add a parametrized constructor that uses an initializer list for name and validates ago > 0
1(b). Create a Person.cpp that implements the functionality of Person.h
Create PersonTest.cpp that demonstrates the features of class Person
What do you mean by three different source files? If you mean Person.h, Person.cpp, and PersonTest.cpp, see below
a .h file (you should actually be using a .hpp file for c++ but it still technically works) is whats called a header file. This is where you would pretty much just name the class and all its attributes/methods, its the bare bones of the class that shows what the class is capable of doing without actually showing how its all done.
Person.cpp would be the file where you implement everything from the .h class. the top of your .h file should have something like this at the top:
#include "Person.cpp"
This tells the .h file where to look for the implementation of the methods you previously declared. To implement a method, all you need to do is something like inside of the cpp file `
void Person::setAge(int newAge) {
---implementation---
}
the "Person::" just shows that you are doing something inside of the Person class.
The third file is probably where your int main() is going to be, and make sure that at the top, it also has the #include for the header. Here is where you do what you want to test if your class is actually working, like checking that your outputs match what you expect, etc etc.
I hope this clarified a little of what you needed!
Given you know what a constructor is, you should add to this file another constuctor :
Person(string name,int age);
in the file Person.cpp you develop all the functions defined in Person.h
The file PersonTest.cpp should have a main function that calls instances of Person and prove your class works
(i have edited my original question to make it more understandable)
here is the prototype for the problem ....
//Txn.h ---this has a static variable, usable by the pgms including it.
class Txn
{
public:
static int i;
static void incr_int();
};
Txn::i=0;
//Txn.cpp
void Txn::incr_int() {i++;}
->produce LibTxn.so
//class1.cpp -> one of the pgm using the static var from Txn.h
#include Txn.h
Txn::incr_int()
-> produce class1.o, with LibTxn.so.
// class2.cpp ->another pgm using the static var from Txn.h
#include Txn.h
cout<<"Txn::i;
-> produce class2.o, by including LibTxn.so
-> .produce class3 (an exe) by using class1.o,class2.o. Since, both class1 and 2 has the statement "Txn::i=0" from "Txn.h", multiple declaration issue happens.
-> .If I remove the statement "Txn::i=0" from Txn.h, then "undefined reference" error appears.
-> .At high lvl, this problem is a kind of having a session variable, which should be assessible from any func in a exe. Those func can be in any obj files used to form the exe. I am fine for any sol, even without static. But I can't change the creation of different .o files (which are using this session var) and combining the .o to produce the exe.
It is hard to figure out exactly what the problem is if you cannot provide the real code, or at least an example which has the same problem as the real code.
However, most likely the root cause of the problem is that you are not only declaring, but also defining your class's static variable in the header file that contains the class definition.
This means that all the translation units (i.e. .cpp files) which include that header will contain a definition for the static variable, and when merging all the corresponding object files, the linker will eventually complain about that symbol being defined multiple times.
If this is the case, what you should do is to take the initialization of the static variable out of the header file which contains your class's definition and put it in one (and only one) .cpp file.
I tried to recreate the problem as you described, but it compiled just fine on my computer, and it is difficult to go further without seeing your code.
In the code below, the header tells (declares) every .cpp file that includes it about Foo::x, but Foo::x lives in (is defined in) Foo.cpp (and Foo.o)
foo.h:
class Foo {
public:
static int x;
};
Foo.cpp:
#include "foo.h"
int Foo::x;
main.cpp:
#include <iostream>
#include "foo.h"
int main(int argc, char *argv[]) {
Foo::x = 42;
std::cout << "Foo::x is " << Foo::x;
}
Yes. it worked by defining the static variable in .cpp.
Special thanks to Andy Prowl and iWerner.
OK folks. I have fixed the error by moving the variable definition, but I do not understand why there is a problem.
Simplified Background: I have an object and I want to track all instances of that object in a list, so I simply created a List<> static member of the class. Below was a simple representation that allowed me to play with it. If I have the line marked as "this line" in the static library. I get a run time error. The object is defined in a header file and is the same header file in both places. If I move "this line" to the code in my final application and it works.... Why? I just don't understand why it is different.
#include "stdafx.h"
#include <list>
using namespace std;
class someobject
{
public:
someobject()
{
// do some stuff.
theStaticList.push_back(this);
}
void func()
{
printf("Made it!!\n");
}
static list<someobject*> theStaticList;
};
list<someobject*> someobject::theStaticList; //*** This line
someobject global;
int main()
{
someobject initial;
initial.func();
global.func();
list<someobject*>::iterator iter;
printf("\n\nLoop the Static List\n");
for (iter = someobject::theStaticList.begin(); iter != someobject::theStaticList.end (); iter++)
(*iter)->func();
return 0;
}
If you put that line in a header file, then include the header into two or more source files, you're defining the list object in each source file where the header gets included.
This violates the one definition rule, so the linker will quite rightly give you an error when you do it.
You want to define the object in one (and only one) source file. For a library, that should be some object file in the library, not the user's source file though (at least as a general rule).