How to import a class in another C++ header file? [duplicate] - c++

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 6 years ago.
I meet a problem when constructing a class. class "Graph" import a class "Bag" in another file and use "Bag" as its component.
//Graph.h
#ifndef GRAPH_H
#define GRAPH_H
#include <fstream>
#include <iostream>
#include <vector>
#include "Bag.h"
class Bag;
class Graph
{
public:
Graph(int V);
Graph(std::ifstream& in_file);
int getV() { return V; }
int getE() { return E; }
void addEdge(int v, int w);
void showadj() ;
private:
int V;
int E;
std::vector<Bag> adj;
};
#endif
And "Bag.h" is as follow:
//Bag.h
#ifndef BAG_H
#define BAG_H
#include <vector>
#include <iostream>
class Bag
{
public:
Bag();
void addBag(int i) { content.push_back(i); }
void showBag();
private:
std::vector<int> content;
};
#endif
Graph.cpp:
//Graph.cpp
#include "Graph.h"
#include "Bag.h"
Graph::Graph(int V) : V(V), E(0)
{
for (int i = 0; i < V; i++)
{
Bag bag;
adj.push_back(bag);
}
}
Bag.cpp(sorry, forget it):
#include "Bag.h"
void Bag::showBag()
{
for (int i : content)
{
std::cout << i << " ";
}
}
When I try to complie these two classes, an error comes out saying:
C:\Users\ADMINI~1\AppData\Local\Temp\ccMj4Ybn.o:newtest.cpp:(.text+0x1a2): undef
ined reference to `Bag::Bag()'
collect2.exe: error: ld returned 1 exit status

You need to also implement your constructor Bag::Bag() as it is missing in your Bag.cpp file.
This is what the error tells you. If you don't need the constructor, then you should remove it from your class definition, which would also solve this error.
An alternative would be to provide an empty constructor in your Bag.h file
class Bag
{
public:
Bag() {}
...
}

Related

undefined reference to `Game::play()' [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 1 year ago.
I get the following error message when I try to invoke Game::play() member function, I've been searching for what could be the error. But I couldn't find it.
Here's Game.h
#pragma once
#include <iostream>
class Game {
public:
void selectPlayer();
// Player* nextPlayer() const;
bool isRunning() const;
void play();
void announceWinner();
};
Game.cpp implementation
#include "Game.h"
void Game::selectPlayer() {
}
bool Game::isRunning() const {
}
void Game::play() {
// while (isRunning()) {
// board.display();
// }
//board.display();
std::cout << "hello\n";
}
void Game::announceWinner() {
std::cout << "Game is over\n";
}
main.cpp
#include <iostream>
#include "Game.h"
int main() {
Game g;
g.play();
}
I get this error when I invoke play(): undefined reference to Game::play()'`
At a glance your code looks okay. I would suggest adding a class constructor to your .h file:
#pragma once
#include <iostream>
class Game {
public:
Game(void);
...
Also ensure you have return 0; at the end of your main still.

Undefined reference when compiling when using header and cpp file with templates in one of them

I've been trying to compile my project and I've encountered some problems when trying so. The error in particular that appears is:
[build] /usr/bin/ld: CMakeFiles/robot_control.dir/main.cpp.o:(.data.rel.ro._ZTVN4comm15cameraInterfaceE[_ZTVN4comm15cameraInterfaceE]+0x10): undefined reference to `comm::Interface<cv::Mat>::callbackMsg()'
My project is organized right now as it follows:
-${HOME_WORKSPACE}
|-main.cpp
|-src
|-communication.cpp
|-communication.hpp
The header file (communication.hpp) is:
#include <opencv2/opencv.hpp>
#include <gazebo/gazebo_client.hh>
#include <gazebo/msgs/msgs.hh>
#include <gazebo/transport/transport.hh>
#include <algorithm>
#ifndef COMM_GUARD
#define COMM_GUARD
namespace comm
{
struct lidarMsg
{
float angle_min, angle_increment, range_min, range_max;
int nranges, nintensities;
std::vector<int> ranges;
};
template <typename T>
class Interface
{
public:
Interface() : received{false} {};
virtual void callbackMsg();
bool receptionAccomplished()
{
return this -> received;
}
T checkReceived()
{
return this -> elementReceived;
}
protected:
bool received;
T elementReceived;
};
class cameraInterface : public Interface<cv::Mat>
{
public:
void callbackMsg(ConstImageStampedPtr &msg);
};
class lidarInterface : public Interface<lidarMsg>
{
public:
void callbackMsg(ConstLaserScanStampedPtr &msg);
};
}
#endif
The source file (communication.cpp) is:
#include <opencv2/opencv.hpp>
#include <algorithm>
#include <iostream>
#include "communication.hpp"
#ifndef COMM_CPP_GUARD
#define COMM_CPP_GUARD
namespace comm
{
void cameraInterface::callbackMsg(ConstImageStampedPtr &msg)
{
std::size_t width = msg->image().width();
std::size_t height = msg->image().height();
const char *data = msg->image().data().c_str();
cv::Mat im(int(height), int(width), CV_8UC3, const_cast<char *>(data));
im = im.clone();
cv::cvtColor(im, im, cv::COLOR_RGB2BGR);
this->elementReceived = im;
received = true;
}
void lidarInterface::callbackMsg(ConstLaserScanStampedPtr &msg) {
this->elementReceived.angle_min = float(msg->scan().angle_min());
this->elementReceived.angle_increment = float(msg->scan().angle_step());
this->elementReceived.range_min = float(msg->scan().range_min());
this->elementReceived.range_max = float(msg->scan().range_max());
this->elementReceived.nranges = msg->scan().ranges_size();
this->elementReceived.nintensities = msg->scan().intensities_size();
for (int i = 0; i < this->elementReceived.nranges; i++)
{
if (this->elementReceived.ranges.size() <= i)
{
this->elementReceived.ranges.push_back(std::min(float(msg->scan().ranges(i)), this->elementReceived.range_max));
}
else
{
this->elementReceived.ranges[i] = std::min(float(msg->scan().ranges(i)), this->elementReceived.range_max);
}
}
}
}
#endif
The main file(main.cpp) includes the following header:
#include <gazebo/gazebo_client.hh>
#include <gazebo/msgs/msgs.hh>
#include <gazebo/transport/transport.hh>
#include <opencv2/opencv.hpp>
#include <opencv2/calib3d.hpp>
#include <iostream>
#include <stdlib.h>
#include "src/communication.hpp"
I included the part of the #ifndef /#define /#endif since it is a solution that I found to this kind of problem in other problem. I've been toggling the CMakeLists.txt file but still no solution that could solve this error.
You can't do this:
virtual void callbackMsg();
You have to actually provide the implementation for all template methods within the .h file.

Inheriting from a template class in c++, fail to compile

My question is that, I have a template class template<class T> AList as base, and I wanna get a derived class from the template, i.e. get class BList: public AList<mydefinedtype> without much modification.
alist.h
#ifndef alist_h
#define alist_h
template<class T> class AList
{
public:
AList(){
arr = new T[20];
numitems = 0;
};
void append(T value);
private:
T *arr;
int numitems;
};
#endif /* alist_h */
alist.cpp
#include "alist.h"
template<class T> void AList<T>::append(T value)
{
arr[numitems] = value;
++numitems;
return;
}
blist.h
#include "alist.cpp"
#include <string>
using namespace std;
typedef struct
{
string a, b;
int key;
} record;
class BList: public AList<record>{
public:
void test(void){
cout << "this is from BList" << endl;
}
};
blist.cpp
#include "blist.h"
main.cpp
#include <iostream>
#include "blist.cpp"
using namespace std;
int main(){
record testRecord[3];
testRecord[0] = {"Mark", "A", 1};
testRecord[1] = {"Anla", "B", 2};
testRecord[2] = {"Cindy", "C", 3};
BList blist = BList();
for(auto i: testRecord){
// blist.append(i); // will compile error
blist.test();
}
return 0;
}
It will fail as follows, I wonder how to compile or how to fix the bug.
error info
Undefined symbols for architecture x86_64:
"AList<record>::append(s)", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
Not sure where comes from the issue.
// Example program
#include <iostream>
#include <string>
struct record{
int a;
};
template<class T>
class AList{
public:
AList()=default;
void append(T value){}
};
template<class T>
class BList:public AList<T>{
public:
void test(void){}
};
int main()
{
BList<record> blist;
record recordarr[3] ;
// some initialization
for(auto i:recordarr){
blist.append(i);
blist.test();
}
}
The problem you have is that the AList() constructor, append(T) and test() are only declared but not defined. The above code should compile.
You should put your template classes entirely in header files. See this question and this C++ FAQ for details on why.
You should also never #include .cpp files. You should only ever #include header files.
Below I have your code after the required modifications to make it compile. I also removed your memory leak.
alist.h:
#ifndef alist_h
#define alist_h
template<class T> class AList {
public:
AList() {
arr = new T[20];
numitems = 0;
};
~AList() {
delete[] arr;
}
void append(T value) {
arr[numitems] = value;
++numitems;
}
private:
T *arr;
int numitems;
};
#endif /* alist_h */
blist.h:
#ifndef blist_h
#define blist_h
#include "alist.h"
#include <string>
using namespace std;
typedef struct {
string a, b;
int key;
} record;
class BList: public AList<record> {
public:
void test(void) {
cout << "this is from BList" << endl;
}
};
#endif /* blist_h */
main.cpp:
#include <iostream>
#include "blist.h"
using namespace std;
int main() {
record testRecord[3];
testRecord[0] = {"Mark", "A", 1};
testRecord[1] = {"Anla", "B", 2};
testRecord[2] = {"Cindy", "C", 3};
BList blist = BList();
for (auto i: testRecord) {
blist.append(i);
blist.test();
}
return 0;
}
Summary of changes
I made the following changes:
Moved body of AList::append into alist.h, and deleted alist.cpp
Added AList destructor to free the dynamically allocated memory allocated in AList::AList
In blist.h, included alist.h instead of alist.cpp
Deleted blist.cpp
In main.cpp, included blist.h instead of blist.cpp

error undefined reference to .. c++? [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 9 years ago.
so I have a class x that is being used by class y and it's also going to be used by other classes.
.h for class x
#pragma once
#include <string>
#ifndef X_H
#define X_H
class x
{
public:
x();
const std::string & getName() const;
int getQuantity();
private:
std::string name;
int quantity;
};
#endif
.cpp for x
#include <string>
#include "x.h"
using namespace std;
x::x()
: name(),quantity(0)
{
}
const string & x::getName() const
{
return name;
}
const string & x::getQuantity() const
{
return quantity;
}
this is the .h for class y
#pragma once
#include <string>
#include <array>
#include "x.h"
class y
{
public:
static const size_t number = 20;
y();
float getTotal();
private:
std::array<X*, number> arrayList;
};
and this is the .cpp for class y
#include "y.h"
#include "x.h"
#include <array>
#include <string>
#include <iostream>
using namespace std;
y::y()
: arrayList()
{
}
float y::getTotal()
{
float total=0.0;
for(int i=0; i< number; i++)
{
if(arrayList[i] != nullptr)
{
total += arrayList[i]->getQuantity();
}
}
}
methods in the y class uses an array of pointers to method y and I'm trying to use some methods from class x using the array members but I get an error saying:
undefined reference to `x::x(...)
I think it has something to do with the preprocessors or the headers.
This means that you forgot to define the default constructor X::X() or some other constructor with parameters ( what does x::x(...) mean?) of class X. You only declared it in the class definition.
Or the other reason is that the module with the constructor definition was not included in the project build.
In class x you have explicitly declared the default constructor x() but you have not defined it. If you want to use the default constructor, remove its definition or define it with x::x():name(std::string()),quantity(0){}

declaring a vector as a class member

I have simple class in a header file: a.hh
#ifndef a_hh
#define a_hh
class a
{
public:
int i;
a()
{
i = 0;
}
};
#endif
Then i have a file:b.cc
#include <iostream>
#include "a.hh"
using namespace std;
int main(int argc, char** argv)
{
a obj;
obj.i = 10;
cout << obj.i << endl;
return 0;
}
>
Till this point everything is fine.
I compile the code and it compiles fine.
But as soon as i add a vector in the class:
#ifndef a_hh
#define a_hh
class a
{
public:
int i;
vector < int > x;
a()
{
i = 0;
}
};
#endif
I get a compilation error as below:
> CC b.cc
"a.hh", line 7: Error: A class template name was expected instead of vector.
1 Error(s) detected.
What is the problem with declaring a vector here as a member?
You need to #include <vector> and use the qualified name std::vector<int> x;:
#ifndef a_hh
#define a_hh
#include <vector>
class a{
public:
int i;
std::vector<int> x;
a() // or using initializer list: a() : i(0) {}
{
i=0;
}
};
#endif
Other points:
(as commented by EitanT) I removed the additional qualification a:: on the constructor
have a read of Why is "using namespace std" considered bad practice?
declaring a vector as a class member:
#include <iostream>
#include <vector>
using namespace std;
class class_object
{
public:
class_object() : vector_class_member() {};
void class_object::add_element(int a)
{
vector_class_member.push_back(a);
}
void class_object::get_element()
{
for(int x=0; x<vector_class_member.size(); x++)
{
cout<<vector_class_member[x]<<" \n";
};
cout<<" \n";
}
private:
vector<int> vector_class_member;
vector<int>::iterator Iter;
};
int main()
{
class_object class_object_instance;
class_object_instance.add_element(3);
class_object_instance.add_element(6);
class_object_instance.add_element(9);
class_object_instance.get_element();
return 0;
}
1.You need to #include <vector> and using namespace std, then a.hh just like below:
#ifndef a_hh
#define a_hh
#include <vector>
using namespace std;
class a
{
public:
int i;
vector <int> x;
a()
{
i = 0;
}
};
#endif
2. If you don't want to only use std namespace in all your code, you can specified the namespace before type, just like std::vector<int> x;