i'm currently working on a program that employs the user of virtual functions. I am using only one virtual function and have come across what seems to be a common problem with a common solution which I have tried but unfortunately to no success.
I originally had virtual void calcArea(); in BasicShape.h without any definition or designation as a pure virtual function. I changed it and added {} at the end (as suggested on another thread with a similar problem) but I still get the following error:
I input:
g++ BasicShape.h BasicShape.cpp circle.h circle.cpp Rectangle.h Rectangle.cpp driver.cpp -o Lab4
And then I get:
/tmp/ccf1Y4Br.o: In function `BasicShape::BasicShape()': circle.cpp:(.text._ZN10BasicShapeC2Ev[_ZN10BasicShapeC5Ev]+0xf): undefined reference to `vtable for BasicShape'
/tmp/ccf1Y4Br.o:(.rodata._ZTI6circle[_ZTI6circle]+0x10): undefined reference to `typeinfo for BasicShape'
/tmp/ccc7gjtH.o:(.rodata._ZTI9Rectangle[_ZTI9Rectangle]+0x10): undefined reference to `typeinfo for BasicShape'
collect2: error: ld returned 1 exit status
Any ideas?
This is the implementation file BasicShape.h:
#ifndef BASICSHAPE_H
#define BASICSHAPE_H
class BasicShape
{
protected:
double area;
public:
double getArea() const;
virtual void calcArea();
};
#endif
The accompanying BasicShape.cpp file:
#include "BasicShape.h"
double BasicShape::getArea() const
{
return area;
}
void BasicShape::calcArea()
{
}
circle.h:
#include "BasicShape.h"
#ifndef CIRCLE_H
#define CIRCLE_H
class circle : public BasicShape
{
private:
long centerX;
long centerY;
double radius;
public:
circle(long, long, double);
long getCenterX() const;
long getCenterY() const;
virtual void calcArea();
};
#endif
circle.cpp:
#include "circle.h"
// constructor
circle::circle(long userIn, long userIn2, double userIn3)
{
centerX = userIn;
centerY = userIn2;
radius = userIn3;
calcArea();
}
// accesors
long circle::getCenterX() const
{
return centerX;
}
long circle::getCenterY() const
{
return centerY;
}
// virtual function
void circle::calcArea()
{
area = (3.14159 * radius * radius);
}
Rectangle.h
#include "BasicShape.h"
#ifndef RECTANGLE_H
#define RECTANGLE_H
class Rectangle : public BasicShape
{
private:
long width;
long length;
public:
Rectangle(long, long);
long getWidth() const;
long getLength() const;
virtual void calcArea();
};
#endif
Rectangle.cpp:
#include "Rectangle.h"
// constructor
Rectangle::Rectangle(long userIn, long userIn2)
{
width = userIn;
length = userIn2;
calcArea();
}
// accessors
long Rectangle::getWidth() const
{
return width;
}
long Rectangle::getLength() const
{
return length;
}
void Rectangle::calcArea()
{
area = (length * width);
}
The driver program is incomplete, but irrelevant to my problem anyway (at least I think so).
#include <cassert>
#include <iostream>
#include "BasicShape.h"
#include "Rectangle.h"
#include "circle.h"
using namespace std;
int main()
{
cout << "Testing the functionality and efficiency of the circle class...\n";
// declare circle object and test accessors and area computation
circle objCircle(8,8,4);
assert(objCircle.getCenterX() == 8);
assert(objCircle.getCenterY() == 8);
assert(objCircle.getArea() == 50.26544);
cout << "Circle object testing completed successfully\n";
cout << "Testing the functionality and efficiency of the Rectangle class...\n";
// declare rectangle object and test accessors and area computation
//Rectangle objRec();
return 0;
}
Actually, as it was pointed out, you have not to compile headers. (Although you can, it is irrelevant here --- gcc will generate precompiled headers).
And more interesting: your example perfectly works here, GCC 4.6.3.
Also, sidenote: calcArea shouldn't be public
You should not tryo to compile the headers:
g++ BasicShape.cpp circle.cpp Rectangle.cpp driver.cpp -o Lab4
Your compiler needs at least one translation unit where a virtual member is defined outside the class definition for each polymorphic class. It will instantiate some internal data for the class (virtual function table, polymorphic typeinfo) only if there is such a translation unit.
(Disclaimer: At least that was the case when I last used it, long ago)
You could either use an out-of-class definition for the BasicShape::calcArea function or add a virtual (optionally even pure virtual) destructor to BasicShape and define it out-of-class. The best place would probably be the BasicShape.cppfile.
BTW: As others have pointed out, you typically should not pass header files as separate translation units to the compiler. This will do no harm (other than inflate your compilation time), but also no good.
Ok, so apparently this all seems to be a compiler issue. This entire time I was using gedit as a text editor and g++ as a compiler, but when I switched over to code blocks it was working just fine.
Related
I am writing unit-tests for a C++ class that has dependencies on 3rd-party C and C++ libraries, as well as 1st-party C libraries. I am running into trouble, because I want the class under test to consume a mocked 3rd-party C library and the test runner to consume the REAL 3rd-party C library.
I am writing unit-tests, and the class under test has a dependency on libx.
I have created a libmockx which allows me to test parameters and inject return values.
The class under test, needs to link to libmockx so I can inspect and control it's behavior.
The unit test application, needs to link to libx in order to formulate/parse libx data types.
Which pattern or method is used to link the test runner to libx, the class under test to libmockx, then link the test-runner to the class under test? Many solutions discuss letting the linker do the "dirty work", but ld has 100s of parameters and I don't know how to make it work.
Currently, I have redefinition errors for all the mock implementations, and I need a way to work around it (whether that involves the linker or not).
EDIT BELOW: (in response to comments)
Imagine 7 files:
test.cpp - the test runner
object.cpp - the object under test
object.hpp - the object header
mock-parameters.h - provide mock parameter access to tests
mock-x.c - the mock implementation of x
x.c - the x implementation
x.h - the x header
Before I needed to instantiate and manipulate x objects, I was able to compile my test with a single call to g++:
g++ test.cpp object.cpp mock_x.c
I am trying to add a test to test.cpp, that will supply and test an x object result value. Now, I need to link test.cpp against x.c while still linking object.cpp against mock_x.c.
When I add x.c to the compilation list, I get the following (expected) error:
/usr/bin/ld: /tmp/ccDVQxtN.o: in function `set_foo(X*, int)':
mock-x.c:(.text+0x0): multiple definition of `set_foo(X*, int)'; /tmp/cc3t8CjP.o:x.c:(.text+0x14): first defined here
collect2: error: ld returned 1 exit status
x.h
#ifndef X_H
#define X_H
typedef struct X {
int foo;
char bar;
} X;
X * create_x (void);
int set_foo (X *, int);
char set_bar (X *, char);
void delete_x (X *);
#endif // X_H
x.c
#include "x.h"
#include "stdlib.h"
X * create_x (void) {
return (X *)malloc(sizeof(X));
}
int set_foo (X * x, int i) {
x->foo = i;
return i;
}
char set_bar (X * x, char c) {
x->bar = c;
return c;
}
void delete_x (X * x) {
free(x);
}
mock-x.c
#include "x.h"
#include "mock-parameters.h"
Set_foo_params set_foo_params;
int set_foo (X * x, int i) {
// Stash parameter(s)
set_foo_params.x = x;
set_foo_params.i = i;
return set_foo_params.result;
}
object.hpp
#ifndef OBJECT_HPP
#define OBJECT_HPP
#include "x.h"
class Object {
public:
void embed_x(X *);
int increment_foo(int);
private:
X * _x;
};
#endif // OBJECT_HPP
object.cpp
#include "object.hpp"
void Object::embed_x (X * x) {
_x = x;
}
int Object::increment_foo (int i) {
++i;
return set_foo(_x, i);
}
mock-parameters.h
#include "x.h"
typedef struct Set_foo_params {
X * x;
int i;
int result;
} Set_foo_params;
extern Set_foo_params set_foo_params;
test.cpp
#include "object.hpp"
#include "mock-parameters.h"
int test_object_update_foo_correctly_invokes_x_set_foo (void) {
int result;
Object object;
// Setup
X * x = create_x();
object.embed_x(x);
// Execute
object.increment_foo(7);
// Test
if (8 == set_foo_params.i) {
result = 0;
} else {
result = 1;
}
delete_x(x);
return result;
}
int test_object_update_foo_correctly_returns_x_set_foo_result (void) {
int result;
Object object;
// Setup
X * x = create_x();
object.embed_x(x);
set_foo_params.result = 5;
// Execute
int output = object.increment_foo(0);
// Test
if (5 == output) {
result = 0;
} else {
result = 2;
}
delete_x(x);
return result;
}
int main (void) {
int result;
result |= test_object_update_foo_correctly_invokes_x_set_foo();
result |= test_object_update_foo_correctly_returns_x_set_foo_result();
return result;
}
Since you clarified that your object.c and test.c use the same functions - but should use different implementations - the only way is to separate those functions in some way. According to ODR (One Definition Rule of C++ programming language) you cannot have two different implementations of the same function/object.
So the only way is to create two separate functions/objects (with a separate names). You can use different names or put the same names in different namespaces.
Example:
x.h:
#ifndef X_H
#define X_H
#ifdef X_DEBUG
#define X mock_x
#else
#define X x
#endif
namespace X {
int foo();
}
#endif // X_H
x.cpp:
namespace x {
int foo()
{
int res = -1;
// rightful implementation
return res;
}
}
mock-x.cpp:
namespace mock_x {
int foo()
{
int res = -1;
// mock implementation
return res;
}
}
object.cpp:
#define X_DEBUG
#include <x.h>
int obj_bar()
{
int res = X::foo(); // uses mock implementation
return res;
}
}
test.cpp:
#include <x.h>
int test_bar()
{
int res = X::foo(); // uses real implementation
return res;
}
}
Obviously this approach is scalable - you can put any number of classes/function/objects in this namespace X. Common functionality may be defined inline in the header <x.h> and separate functionality in corresponding modules x.c and mock-x.c.
In general:
I would definitely look in the direction of creating mock-x implementation as a distinct set of linker symbols. This is definitely much more controllable and flexible approach. You can even use original x API implementation from your mock-x functionality - e.g. as a fallback when appropriate.
EDIT:
For your specific newly added example code.
mock-x.c:
#include "x.h"
#include "mock-parameters.h"
Set_foo_params set_foo_params;
int mock_set_foo (X * x, int i) {
// Stash parameter(s)
set_foo_params.x = x;
set_foo_params.i = i;
return set_foo_params.result;
}
The rest of the files are unchanged.
GCC should compile object.cpp separately with command:
g++ -Dset_foo=mock_set_foo -c object.cpp -o object.o
g++ test.cpp object.o x.c mock_x.c
GCC option -Dset_foo=mock_set_foo works the same as
#define set_foo mock_set_foo
in the beginning of each source file in command line after this option.
This option is widely used for compile-time configuration purposes.
I want to have a singleton in my project but some errors occur
this is my codes in three separate files.:
//---------------My main.cpp code
#include <iostream>
#include "Sports/BBVB.h"
int main() {
bbvb;
return 0;
}
// ---------------------------my BBVB.h code
#ifndef SAMAVAR_BBVB_H
#define SAMAVAR_BBVB_H
typedef struct VBResult{
int set1=-1;
int set2=-1;
int set3=-1;
int set4=-1;
int set5=-1;
}VBResult;
#include "Sport.h"
#include "../TournamentStuf/Tournament.h"
class BBVB: public Sport {
protected:
vector<Tournament<VBResult>> tours;
public:
static BBVB& getInstance(){
static BBVB b;
return b;
}
private:
BBVB(){}
public:
BBVB(BBVB const&)=delete;
void operator=(BBVB const&) = delete;
//-------------Setter------------
//------------Getter-------------
vector<Tournament<VBResult>> getTours() const;
Tournament<VBResult> getTourById(int id) const;
//----------Others---------------
void addTour(Tournament<VBResult> v);
};
BBVB &bbvb=BBVB::getInstance();
#endif //SAMAVAR_BBVB_H
//------------------my Store and restore code
#ifndef SAMAVAR_STOREANDRESTORE_H
#define SAMAVAR_STOREANDRESTORE_H
#include "../Sports/BBVB.h"
#include "../Sports/PingPong.h"
#include "../Sports/Wrestling.h"
void Start(BBVB &b);
void Update(const BBVB &b);
void Start(PingPong &p);
void Update(const PingPong &p);
void Start(Wrestling &w);
void Update(const Wrestling &w);
#endif //SAMAVAR_STOREANDRESTORE_H
I have a bbvb instance of BBVB but it says you have multiple definitions of it.
I'm new to Clion and I don't have enough information about somethings like cmake and I feel the problem is because of it.
I want to have something like cout and cin in iostream.so by including my BBVB I can access this object.
Clion shows error below:
CMakeFiles\Samavar.dir/objects.a(BBVB.cpp.obj):BBVB.cpp:(.bss+0x0): multiple definition of `bbvb'
CMakeFiles\Samavar.dir/objects.a(main.cpp.obj):main.cpp:(.bss+0x0): first defined here
CMakeFiles\Samavar.dir/objects.a(StoreAndRestore.cpp.obj):StoreAndRestore.cpp:(.bss+0x0): multiple definition of `bbvb'
CMakeFiles\Samavar.dir/objects.a(main.cpp.obj):Samavar-master/Sports/BBVB.h:24: first defined here
collect2.exe: error: ld returned 1 exit status
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.
I am currently working on a virtual run time environment program that is at a very early stage, i am prevented from continuing my work due to a linker error when using my makefile, provided below. The error i am receiving is:
g++ controller.o processor.o test.o -o final
controller.o: In function `Controller::run()':
controller.cpp:(.text+0x1e0): undefined reference to
Processor::codeParams(char)'
controller.o: In function `Controller::fetch()':
controller.cpp:(.text+0x290): undefined reference to `Controller::pc'
controller.cpp:(.text+0x299): undefined reference to `Controller::pc'
collect2: error: ld returned 1 exit status
makefile:16: recipe for target 'final' failed
make: *** [final] Error 1
I am unsure as to why i get this error as i thought i had defined these things in the source file corresponding to the header. All files will be given below so that the program can be compiled.
test.cpp:
#include <iostream>
#include <vector>
#include "includes/controller.h"
using namespace std;
int main()
{
vector<char> prog = {0x0};
Controller contr(prog);
cout << "Error Code: " << contr.run() << endl;
return 0;
}
controller.cpp:
/*
Author(s): James Dolan
File: controller.cpp
Build: 0.0.0
Header: includes/controller.h
DoLR: 21:39 11/1/2017
Todo: n/a
*/
#include "includes/controller.h"
Controller::Controller(vector<char> prog)
{
printf("Program:"); //Display program
for(auto i : program)
{
printf("%02X", i);
}
printf("\n");
Controller::program = program;
}
Controller::~Controller ()
{
}
int Controller::run()
{
bool runFlag = true;
int errorCode = 0;
char curCode;
vector<char> curInstr;
int paramRef;
while(runFlag)
{
curCode = fetch();
printf("curCode:%02X\n", curCode);
curInstr.push_back(curCode);
paramRef = proc.codeParams(curCode);
if (paramRef == 0xffff){runFlag = false; continue;} //Check if shutdown signal was returned, if so shutdown
printf("opcode good\n");
for(int i; i<paramRef; i++){curInstr.push_back(fetch());}
}
return errorCode;
}
char Controller::fetch()
{
return program[pc++]; //Return next instruction then increment the program counter
}
controller.h:
/*
Author(s): James Dolan
File: controller.h
Source: ../controller.cpp
DoLR: 21:39 11/1/2017
Todo: n/a
*/
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <iostream>
#include <vector>
#include <cstdlib>
#include "processor.h"
using namespace std;
class Controller{
public:
Controller(vector<char> prog);
~Controller();
int run();
protected:
private:
vector<char> program;
static int pc;
char fetch();
Processor proc();
};
#endif
processor.cpp:
#include "includes/processor.h"
Processor::Processor()
{
}
Processor::~Processor()
{
}
int codeParams(char code)
{
switch(code)
{
case 0x0: //Halt
return 0;
default:
printf("[ERROR!] Invalid opcode [%02X]", code);
return 0xffff; //Return shutdown signal
}
}
processor.h:
#ifndef PROCESSOR_H
#define PROCESSOR_H
#include <iostream>
#include <cstdlib>
class Processor{
public:
Processor();
~Processor();
int codeParams(char code);
protected:
private:
};
#endif
All if any help is appreciated massively as it will help me to continue with my passion of developing a fully fledged open-source virtual runtime enviroment like the java vm, thank you for your time.
In Controller.cpp you need a int Controller::pc; or int Controller::pc = 0;
In the header file you declared a static int named pc that exists somewhere. It needs to actually exist in a translation unit somewhere (in this case Controller.cpp) so that when the linker tries to find it... it exists.
In Processor.cpp your signature should look like int Processor::codeParams(char code) to let the compiler know that is Processor's codeParams and not a random function named codeParams that happens to also take a character.
For the member function Processor::codeParams you should define it as:
int Processor::codeParams(char code)
// ~~~~~~~~~~~
{
...
}
Otherwise it's just a normal (non–member) function.
For the static member Controller::pc you should define it outside of the class definition, in controller.cpp.
// Controller.h
class Controller {
...
private:
static int pc;
};
// controller.cpp
int Controller::pc;
I'm trying to build a C++ project for a course I'm following and I'm having a lot of troubles.
I have this header:
#ifndef COMPTE_H_
#define COMPTE_H_
#include <string>
class Compte {
public:
Compte (unsigned int p_noCompte, double p_tauxInteret, double p_solde,const std::string& p_description);
virtual ~Compte (){} ;
void asgSolde (const double p_solde);
unsigned int reqNoCompte () const;
double reqTauxInteret () const;
double reqSolde () const;
std::string reqDescription () const;
std::string reqCompteFormate() const;
virtual Compte* clone() const;
virtual const double calculerInteret();
private:
unsigned int m_noCompte;
double m_tauxInteret;
double m_solde;
std::string m_description;
};
#endif /* COMPTE_H_ */
And the corresponding cpp file:
#include "Compte.h"
#include <string>
#include <sstream>
using namespace std;
Compte::Compte (unsigned int p_noCompte, double p_tauxInteret, double p_solde, const string& p_description)
: m_noCompte(p_noCompte), m_tauxInteret(p_tauxInteret), m_solde(p_solde), m_description(p_description)
{
}
void Compte::asgSolde (const double p_solde)
{
m_solde = p_solde;
}
unsigned int Compte::reqNoCompte () const{
return m_noCompte;
}
double Compte::reqTauxInteret() const{
return m_tauxInteret;
}
double Compte::reqSolde() const{
return m_solde;
}
string Compte::reqDescription() const{
return m_description;
}
string Compte::reqCompteFormate()const
{
ostringstream compteFormate;
return compteFormate.str();
}
However I have the following errors popping:
Description Resource Path Location Type
undefined reference to « vtable for Compte » Compte.cpp /Travail Pratique 2 line 14 C/C++ Problem
For the constructor in the .cpp file,
Description Resource Path Location Type
undefined reference to « vtable for Compte » Compte.cpp /Travail Pratique 2 line 14 C/C++ Problem
For the class Compte{ line in the .header file, and lastly
Description Resource Path Location Type
undefined reference to « vtable for Compte » Compte.h /Travail Pratique 2 line 16 C/C++ Problem
For the virtual ~Compte(){}; line.
What's wrong with my code, how can I correct this?
You forgot to implement 2 virtual methods, the clone and the calculerInteret.
That is why your linker is complaining. Your linker is not complaining about the destructor but he has trouble creating the virtual method table because 2 methods that are marked virtual, are missing.
Only a linker can find issues like that because in theory these methods can even be spread over multiple source files.
If it is your intent to create abstract methods do this :
virtual Compte* clone() const=0;
virtual const double calculerInteret()=0;
of course you realise you cannot instantiate classes that have abstract methods right ?
Not the problem in this case but may be the problem for anyone viewing this post:
Forgetting a body on a virtual destructor generates the following:
undefined reference to `vtable for CYourClass'.
I am adding a note because the error message is deceptive. (This was with gcc version 4.6.3.)
So add:
Compte::~Compte()
{
}
To your cpp file.
EDIT 1: As pointed out by Philip Stuyck: If the destructor were missing , then you would have had a similar error, but you can have it for any missing virtual method. If the virtual is inline yes or no does not matter, you just need one if its virtual.