So, I am trying to learn c++ and a little bit about makefiles. However, for some reason I cannot get my files to link properly. The makefile is the following:
OBJS = stl_test.o src/t_stack.o src/matrix_w.o src/matrix.o
stl_test: $(OBJS)
g++ -o stl_test $(OBJS) -lm
.cpp.o:
g++ -c -O -I. $< -o $# -std=c++0x
stl_test.o: include/t_stack.h
src/matrix.o: include/matrix.h
src/matrix_w.o: include/matrix_w.h
src/t_stack.o: include/t_stack.h
include/matrix_w.h: include/matrix.h
touch include/matrix_w.h
include/t_stack.h: include/matrix_w.h include/matrix.h
touch include/t_stack.h
The problem that i am currently having is the following:
touch include/matrix_w.h
touch include/t_stack.h
g++ -c -O -I. stl_test.cpp -o stl_test.o -std=c++0x
g++ -c -O -I. src/t_stack.cpp -o src/t_stack.o -std=c++0x
g++ -c -O -I. src/matrix_w.cpp -o src/matrix_w.o -std=c++0x
g++ -c -O -I. src/matrix.cpp -o src/matrix.o -std=c++0x
g++ -o stl_test stl_test.o src/t_stack.o src/matrix_w.o src/matrix.o -lm
src/t_stack.o: In function `T_stack::pop()':
t_stack.cpp:(.text+0xc9): undefined reference to `Matrix<double>::display() const'
t_stack.cpp:(.text+0xd7): undefined reference to `Matrix<double>::~Matrix()'
src/t_stack.o: In function `T_stack::push_translation(double, double, double)':
t_stack.cpp:(.text+0x1af): undefined reference to `Matrix<double>::Matrix(int, int, double*)'
t_stack.cpp:(.text+0x239): undefined reference to `Matrix<double>::multiply(Matrix<double>*) const'
src/t_stack.o: In function `T_stack::push_scaling(double, double, double)':
t_stack.cpp:(.text+0x33f): undefined reference to `Matrix<double>::Matrix(int, int, double*)'
t_stack.cpp:(.text+0x3c9): undefined reference to `Matrix<double>::multiply(Matrix<double>*) const'
src/t_stack.o: In function `T_stack::T_stack()':
t_stack.cpp:(.text+0x4f4): undefined reference to `Matrix<double>::Matrix(int, int, double*)'
t_stack.cpp:(.text+0x516): undefined reference to `Matrix<double>::copy() const'
src/t_stack.o: In function `T_stack::~T_stack()':
t_stack.cpp:(.text+0x64c): undefined reference to `Matrix<double>::display() const'
t_stack.cpp:(.text+0x65a): undefined reference to `Matrix<double>::~Matrix()'
t_stack.cpp:(.text+0x74f): undefined reference to `Matrix<double>::display() const'
collect2: ld returned 1 exit status
make: *** [stl_test] Error 1
I am not entirely sure what the problem is. I tried changing the order of the files in the g++ command but that didnt work either. I have tried checking the headers of the files and I think they are correct but I have posted fragments here anyways:
stltest.cpp
#include <iostream>
#include "include/t_stack.h"
using namespace std;
int main(void) {
......
matrix.h
#ifndef _MATRIX_
#define _MATRIX_
#include <iostream>
using namespace std;
......
matrix_w.h
#ifndef _MATRIX_W_
#define _MATRIX_W_
#include "include/matrix.h"
class Matrix_w {
......
t_stack.h
#ifndef _T_STACK_H_
#define _T_STACK_H_
#include <list>
#include <stack>
#include <iostream>
#include "include/matrix.h"
#include "include/matrix_w.h"
using namespace std;
class T_stack {
private:
// matrix stack
stack<Matrix_w*, list<Matrix_w* > >* m_stack;
// inverse transform list
list<Matrix<double>* >* t_list;
public:
T_stack();
void pop();
void push_translation(double tx, double ty, double tz);
void push_scaling(double sx, double sy, double sz);
int size() const;
~T_stack();
};
#endif
Any ideas what the problem might be? Thanks!
Just in case, here is the implementation of the methods that it complains about (the file is called matrix.cpp)..
#include "include/matrix.h"
using namespace std;
template <typename T>
Matrix<T>::~Matrix() {
delete data;
}
template <typename T>
Matrix<T>::Matrix(int width, int height) {
this->height = height;
this->width = width;
this->data = new T[height*width];
}
template <typename T>
Matrix<T>::Matrix(int width, int height, T* data) {
this->height = height;
this->width = width;
this->data = new T[height*width];
int i;
//may be able to speed this up by using memcpy
// Not sure whether this is a good idea anyways
for(i=0; i < height*width; i++) {
this->data[i] = data[i];
}
}
template <typename T>
T Matrix<T>::at(int x, int y) const {
#ifdef __DEBUG
if(x < width && y < height) {
return data[y*width + x];
} else {
throw 1;
}
#else
return data[y*width + x];
#endif
}
template <typename T>
void Matrix<T>::set(int x, int y, T val) {
#ifdef __DEBUG
if(x < width && y < height) {
data[y*width + x] = val;
} else {
throw 1;
}
#else
data[y*width + x] = val;
#endif
}
//this function is just for convenience but it should only work
//when T is some number type ----ASK!!
template <typename T>
void Matrix<T>::display() const {
int i, j;
cout << "[" << endl;
for(i=0; i<height; i++) {
for(j=0; j<width; j++) {
cout << " " << data[i*width + j];
}
cout << endl;
}
cout << "]" << endl;
}
template <typename T>
Matrix<T>* Matrix<T>::multiply(Matrix<T>* other) const {
#ifdef __DEBUG
if(other->height != width) {
throw 1;
}
#endif
T* res = new T[other->width*height];
int i,j,k;
T sum;
for(i=0; i<height; i++) {
for(j=0; j<other->width; j++) {
sum = 0;
for(k=0; k<width; k++) {
sum += other->data[k*other->width+j]*data[i*width+k];
}
res[i*other->width + j] = sum;
}
}
return new Matrix<double>(other->width, height, res);
}
template <typename T>
Matrix<T>* Matrix<T>::copy() const {
return new Matrix<T>(width, height, data);
}
When you have a template class or functions, the functions should be inline, and the body should be in the header file, in the class or outside with inline keyword in the class.
The difference is that, unlike regular class, the compiler is compiling the class for each type you are using as the template type.
If you are not using it at all, the file won't be compiled even once.
In several compilers your code will work even if it split to h and cpp. but you can't count on it.
I see, it would be typical to implement your template as inline functions. You can, however, use an explicit instantiation of the template in your matrix.cpp file. At the bottom, after the definitions, you could try to add:
template class Matrix<double>;
If you're not using precompiled headers, this actually might make a lot of sense. Also, it can go pretty much anywhere I think, but you can only have one of those statements per program, if you instantiate a Matrix in two places it may or may not work.
Related
I'm coding a spreadsheet built up of column vectors and cell vectors, where
each cell is a placeholder for a cell value. CellValueBase is the base class, CellValue is the final template class.
This is the error:
g++ Cell.o Column.o sheet.o main.o -o spreadsheet
sheet.o: In function `CellValueBase::CellValueBase()':
sheet.cc:(.text+0x0): multiple definition of `CellValueBase::CellValueBase()'
Column.o:Column.cc:(.text+0x0): first defined here
sheet.o: In function `CellValueBase::CellValueBase()':
sheet.cc:(.text+0x0): multiple definition of `CellValueBase::CellValueBase()'
Column.o:Column.cc:(.text+0x0): first defined here
main.o: In function `CellValueBase::CellValueBase()':
main.cc:(.text+0x0): multiple definition of `CellValueBase::CellValueBase()'
Column.o:Column.cc:(.text+0x0): first defined here
main.o: In function `CellValueBase::CellValueBase()':
main.cc:(.text+0x0): multiple definition of `CellValueBase::CellValueBase()'
Column.o:Column.cc:(.text+0x0): first defined here
Cell.o: In function `CellValueBase::~CellValueBase()':
Cell.cc:(.text._ZN13CellValueBaseD2Ev[_ZN13CellValueBaseD5Ev]+0xd): undefined reference to `vtable for CellValueBase'
Cell.o: In function `CellValueBase::CellValueBase()':
Cell.cc:(.text._ZN13CellValueBaseC2Ev[_ZN13CellValueBaseC5Ev]+0x9): undefined reference to `vtable for CellValueBase'
Cell.o:(.rodata._ZTI9CellValueIfE[_ZTI9CellValueIfE]+0x10): undefined reference to `typeinfo for CellValueBase'
Column.o: In function `CellValueBase::CellValueBase()':
Column.cc:(.text+0x9): undefined reference to `vtable for CellValueBase'
sheet.o: In function `CellValueBase::CellValueBase()':
sheet.cc:(.text+0x9): undefined reference to `vtable for CellValueBase'
main.o: In function `CellValueBase::CellValueBase()':
main.cc:(.text+0x9): undefined reference to `vtable for CellValueBase'
collect2: error: ld returned 1 exit status
Makefile:8: recipe for target 'Spreadsheet' failed
make: *** [Spreadsheet] Error 1
And this is my code:
main.cc
#include <iostream>
#include "sheet.h"
using namespace std;
int main () {
Sheet *sht;
sht = new Sheet ();
return 0;
}//main
sheet.h
#ifndef SHEET_H
#define SHEET_H
#include "Column.h"
// Vaste grootte van de sheet
const int AantReg = 24;
const int AantKol = 80;
class Sheet
{
public:
Sheet ();
void getCell();
void begin();
void end();
private:
std::vector<Column*> sheetCol;//bevat de columns
int regels, kolommen;
};
#endif
sheet.cc
#include <iostream>
#include "sheet.h"
using namespace std;
Sheet::Sheet () {
regels = AantReg;
kolommen = AantKol;
cout << "Kolommen" << endl;
for (int i = 0; i < kolommen; i++) {
cout << "kolomnr: " << i << endl;
sheetCol.push_back(new Column(regels));
}
cout << endl << endl;
}
void Sheet::getCell () {
//TODO: fixen
}
void Sheet::begin () {
//TODO: deze shit ook fixen
}
void Sheet::end () {
}
Column.h
#include <vector>
#include "Cell.h"
class Column
{
public:
Column (int n);
//void getCell();
//void begin();
//void end();
private:
int aantCellen;
std::vector<Cell*> columnVec;//sla je de cellen in op
};
#endif
Column.cc
#include <iostream>
#include "Column.h"
using namespace std;
Column::Column(int n): aantCellen(n)
{
for (int i = 0; i < aantCellen; i++) {
cout << "celnr: " << i << endl;
columnVec.push_back(new Cell());
}
}//cell
Cell.h
#ifndef CELL_H
#define CELL_H
#include "CellValueBase.h"
#include <string>
#include <memory>
class Cell {
public:
Cell();
void setValueFloat(float newValue);
//void setValueInt(int newValue);
//void setValueString(std::string newValue);
//void setValueFormula(std::string newValue);
//std::unique_ptr<cellValueBase> readValue();
void emptyCell();
private:
std::unique_ptr<CellValueBase> value;
};
#endif
Cell.cc
#include "Cell.h"
#include <iostream>
using namespace std;
Cell::Cell() {
value.reset(nullptr);
cout << "hallo wereld ik ben een cel" << endl;
setValueFloat(3.14);
} // Cell
void Cell::setValueFloat(float newValue)
{
value = unique_ptr<CellValueBase>(new CellValue<float>(newValue));
value->returnValueNumber();
} // setValueFloat
CellValueBase.h
#ifndef CELLVALUEBASE_H
#define CELLVALUEBASE_H
#include <iostream>
#include <string>
#include <sstream>
#include <stdexcept>
class CellValueBase
{
public:
CellValueBase();
virtual ~CellValueBase() {};
//virtual std::string returnValueStringEdit() = 0;
virtual float returnValueNumber();
void emptyCell();
private:
};
CellValueBase::CellValueBase()
{
} // CellValueBase
template<typename T>
class CellValue final : public CellValueBase
{
public:
CellValue(T initial_value)
: CellValueBase(), value(initial_value)
{ }
~CellValue();
//std::string returnValueString();
//std::string returnValueStringEdit();
float returnValueNumber();
private:
T value;
};
template<typename T>
CellValue<T>::~CellValue()
{
// TODO
}
template<typename T>
float CellValue<T>::returnValueNumber() {
return value;
}
And the makefile:
CC = g++
CompileParms = -c -std=c++14 -Wall -Wextra
OBJS = Cell.o Column.o sheet.o main.o
Spreadsheet: $(OBJS)
$(CC) $(OBJS) -o spreadsheet
Cell.o: Cell.cc CellValueBase.h Cell.h
$(CC) $(CompileParms) Cell.cc
Column.o: Column.cc Column.h
$(CC) $(CompileParms) Column.cc
sheet.o: sheet.cc sheet.h
$(CC) $(CompileParms) sheet.cc
main.o: main.cc sheet.h
$(CC) $(CompileParms) main.cc
You have correctly understood that templates needs to be defined in their header file. But the class CellValueBase is not a template, so the definition of the CellValueBase constructor in the header file is incorrect. It means the constructor will be defined everywhere the header file is included.
The simple solution? Define the CellValueBase constructor inline in the class (like you already do with the destructor).
Furthermore, all virtual but non-abstract functions in a class must have a definition. So either make CellValueBase::returnValueNumber abstract or have an empty definition.
All in all, the CellValueBase class could look like this:
class CellValueBase
{
public:
CellValueBase() {} // <- Define inline
virtual ~CellValueBase() {};
//virtual std::string returnValueStringEdit() = 0;
virtual float returnValueNumber() = 0; // <- Declare abstract
void emptyCell();
private:
};
Look at CellValueBase.h. You can not define non-inline class methods outside of the class in header files. You must define them in .cpp files.
Move this method's definition to to CellValueBase.cpp:
CellValueBase::CellValueBase()
{
} // CellValueBase
Define non-inline methods or functions in header is totally bad practice. Error appears not at once, it appears only when you include this header in two cpp files. It means that linker founds two same methods definitions and that is the problem. If you would leave definition in your header CellValueBase.h and include CellValueBase.h once in .cpp file then there won't be any problems. But when you include CellValueBase.h more than once then linker founds duplicate definition.
But even if you know that you won't include header file with non-inline methods definitions more then once then you also should remember never to define non-inline functions or class methods outside classes. You can forget about your "1 include rule" for this file and later include it twice and linker will detect duplicate definition.
Also you can define template methods without specialization or define inline specialized template methods in header files.
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 8 years ago.
I'm trying to make a simple bounds checked array in C++. I have declared a class in a header file, and defined the class in a separate source file. The compile step runs fine, but when I try to link the objects, I get the following error:
$ g++.exe -o a.exe src\main.o src\array.o
src\main.o: In function `main':
../src/main.cpp:7: undefined reference to `Array<int>::Array(int)'
../src/main.cpp:9: undefined reference to `Array<int>::operator[](int)'
../src/main.cpp:10: undefined reference t o `Array<int>::operator[](int)'
../src/main.cpp:11: undefined reference t o `Array<int>::operator[](int)'
../src/main.cpp:13: undefined reference t o `Array<int>::operator[](int)'
../src/main.cpp:7: undefined reference to `Array<int>::~Array()'
../src/main.cpp:7: undefined reference to `Array<int>::~Array()'
collect2.exe: error: ld returned 1 exit status
main.cpp
#include <iostream>
#include "array.hpp"
using namespace std;
int main() {
Array<int> x(10); // compiler error
x[0] = 1; // compiler error
x[1] = 2; // compiler error
x[2] = 3; // compiler error
cout << x[1] << endl; // compiler error
return 0;
}
array.hpp
#ifndef ARRAY_HPP_
#define ARRAY_HPP_
template <class T>
class Array{
private:
T* array;
int length_;
public:
Array(int);
~Array();
int Length();
int& operator[](int);
};
#endif /* ARRAY_HPP_ */
array.cpp
#include "array.hpp"
template <class T>
Array<T>::Array(int size) {
length_ = size;
array = new T[size];
}
template <class T>
Array<T>::~Array() {
delete[] array;
}
template <class T>
int Array<T>::Length() {
return length_;
}
template <class T>
int& Array<T>::operator[](const int index) {
if (index < 0 || index >= length_) {
throw 100;
}
return array[index];
}
Definitions of members of a template class shall be in the same header where the template class is defined itself.
Template classes must have all their code in the header file or they can only be used for types you explicitly instantiated in the cpp file.
I am porting some windows code that compiles like would expect under msvc 10, but I am having trouble with it linking under g++ 4.8 and/or clang 3.5.
masks.h
#ifndef MASKS_H
#define MASKS_H
#include <boost/array.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
namespace MASKS
{
// ------------------------------------------------- power function
template<class TYPE, uint32_t Base, uint32_t Power>
struct Pow
{
static const TYPE tmp = Pow<TYPE, Base, Power / 2>::value;
static const TYPE value = (Power % 2 == 0) ? (tmp * tmp) : (Base * tmp * tmp);
};
template<class TYPE, uint32_t Base>
struct Pow<TYPE, Base, 0>
{
static const TYPE value = 1;
};
template<class TYPE, uint32_t Base>
struct Pow<TYPE, Base, 1>
{
static const TYPE value = Base;
};
// ------------------------------------------------- mask function
template<class TYPE, int Val>
struct Mask
{
static const TYPE value = Pow<TYPE, 2, Val>::value - 1;
};
template<class TYPE>
struct Mask<TYPE, 64>
{
static const TYPE value = 0xffffffffffffffff;
};
//#define MASK(z, n, text) (MASKS::Mask<uint64_t, n>::value)
static const boost::array<uint64_t, 4> s_Masks =
boost::assign::list_of<uint64_t>
(MASKS::Mask<uint64_t, 0>::value)
(MASKS::Mask<uint64_t, 1>::value)
(MASKS::Mask<uint64_t, 2>::value)
(MASKS::Mask<uint64_t, 3>::value)
//BOOST_PP_REPEAT_FROM_TO (0, 65, MASK, text)
;
inline uint64_t GetMask (size_t iLen) { return MASKS::s_Masks[iLen]; }
} // namespace MASKS
#endif // MASKS_H
main.c
#include <iostream>
#include "masks.h"
int main (int /*argc*/, char */*argv*/[])
{
std::cout << "63 bit mask: " << std::hex << std::showbase << MASKS::GetMask (63) << std::endl;
return 0;
}
When I compile it will not link and gives the following error:
g++ masks.cpp -o mask -std=c++11 -pedantic -Wall -Wextra
tmp/ccYZ0MMb.o: In function `__static_initialization_and_destruction_0(int, int)':
masks.cpp:(.text+0xd9): undefined reference to `MASKS::Mask<unsigned long long, 0>::value'
masks.cpp:(.text+0xea): undefined reference to `MASKS::Mask<unsigned long long, 1>::value'
masks.cpp:(.text+0xfe): undefined reference to `MASKS::Mask<unsigned long long, 2>::value'
masks.cpp:(.text+0x10f): undefined reference to `MASKS::Mask<unsigned long long, 3>::value'
collect2: error: ld returned 1 exit status
I am not sure what I am forgetting here. I expected the TMP objects/functions to get translated to values by the compiler and stored in the array of masks I am trying to build. I am rusty on my g++ syntax I guess. Can anyone see what I've done wrong?
Thanks.
This week I started to upgrade my knowledge from C to C++, I would like to overload some operators
I have a class called Matrix
#include "lcomatrix.h"
inline Matrix::Matrix(unsigned rows, unsigned cols) :
rows_(rows), cols_(cols)
{
data_ = new double[rows * cols];
}
inline Matrix::~Matrix() {
delete[] data_;
}
inline double& Matrix::operator()(unsigned row, unsigned col) {
return data_[cols_ * row + col];
}
inline double Matrix::operator()(unsigned row, unsigned col) const {
return data_[cols_ * row + col];
}
The content of lcomatrix.h is
#include <iostream>
class Matrix {
public:
Matrix(unsigned rows, unsigned cols);
double& operator()(unsigned row, unsigned col);
double operator()(unsigned row, unsigned col) const;
~Matrix(); // Destructor
Matrix& operator=(Matrix const& m); // Assignment operator
private:
unsigned rows_, cols_;
double* data_;
};
Main.cpp
#include "lcomatrix.h"
#include <iostream>
/*-
* Application entry point.
*/
int main(void) {
Matrix mx(12,12);
//std::cout << mx << std::endl;
return 0;
}
Make file:
CPPFLAGS=-I /path/lcomatrix/
EFLAGS=
all : main.o lcomatrix.o
g++ $(EFLAGS) -o main.out main.o lcomatrix.o
main.o: lcomatrix.o
g++ $(EFLAGS) $(CPPFLAGS) -c main.cpp
lcomatrix.o:
g++ $(EFLAGS) -c /home/robu/UbuntuOne/ChibiOS-RPi/lcomatrix/lcomatrix.cpp
clean:
rm *.o main.out
When I try to build I receive the following link error:
make all
g++ -c /home/robu/UbuntuOne/ChibiOS-RPi/lcomatrix/lcomatrix.cpp
g++ -I /home/robu/UbuntuOne/ChibiOS-RPi/lcomatrix/ -c main.cpp
g++ -o main.out main.o lcomatrix.o
main.o: In function `main':
main.cpp:(.text+0x1b): undefined reference to `Matrix::Matrix(unsigned int, unsigned int)'
main.cpp:(.text+0x2c): undefined reference to `Matrix::~Matrix()'
collect2: error: ld returned 1 exit status
make: *** [all] Error 1
I guess this a really stupid error, but as a beginner I couldn't figure out the solution.
Your method definitions are all inline. In order to inline a function, the compiler needs to see its definition whenever it is compiling the code that uses it.
Either put the function definitions somewhere they can be seen at the point of use - in the header, or in another file #included by Main.cpp - or don't mark them as inline.
This is the error I am keep getting . undefined reference to my class. I am not sure. I think I m linking them. this is how my main looks like.
#include <iostream>
#include "randomNumberMagnifier.h"
using namespace std;
int main()
{
randomNumberMagnifier r1, r2;
cout << "Random Number "<< r1.getRandomNumber();
cout << endl;
}
I am not sure what I am doing wrong.
this is what it looks like. when I compile
[singha1#cs1 p4]$ g++ -c randomNumberMagnifier.cpp
[singha1#cs1 p4]$ g++ -o p4Driver.cpp
g++: no input files
p4Driver.cpp:(.text+0x8c): undefined reference to `randomNumberMagnifier::getRandomNumber
collect2: ld returned 1 exit status
#ifndef RANDOMNUMBERMAGNIFIER_H
#define RANDOMNUMBERMAGNIFIER_H
class randomNumberMagnifier
{
int addFactor;
int multFactor;
bool addOn;
bool multOn;
int randomNumber;
static const int MAX_ADD_FACTOR = 100;
static const int MAX_MULT_FACTOR = 20;
static const int MAX_RANDOM = 200;
public:
randomNumberMagnifier();
//~randomNumberMagnifer();
randomNumberMagnifier& operator=(const randomNumberMagnifier& rhs);
randomNumberMagnifier(const randomNumberMagnifier& arandom);
randomNumberMagnifier(bool aState, bool mState);
int randomMagnifier();
int getAdd();
int getMult();
bool getAddState();
bool getMultState();
int getRandomNumber();
};
#endif
g++ -o p4Driver.cpp
That doesn't say what it's supposed to compile to, which is what -o is supposed to be for. You want:
g++ -c randomNumberMagnifier.cpp
g++ -c p4Driver.cpp
g++ randomNumberMagnifier.o p4Driver.o -o p4Driver
Or just:
g++ randomNumberMangifier.cpp p4Driver.cpp -o p4Driver
you need to provide randomNumberMagnifier.o to g++ command, so it can find function definition. I tested with below command and i worked
g++ -o p4Driver p4Driver.cpp randomNumberMagnifier.o