undefined reference with member functions using g++ - c++

For some reasons, sometimes when I define my member functions in a CPP file rather than within their declaring header, I get undefined reference errors from g++.
This question is similar to Undefined Reference To Member function but that user managed to solve the problem by adding the missing file to his command line, which doesn't seem to be working here.
Btw, I'm not against using a makefile; in fact I plan to do so eventually, whenever I get used to these commands.
my main file ('ringbuftest.cpp'):
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <iostream>
#include <cstring>
#include "ringbuffer.h"
using namespace std;
void *reader(void* param);
void *writer(void* param);
struct pack{
char msg[256];
};
RINGBUFFER<pack> *ringo;
int main(){
pthread_t rdr;
pthread_t wtr;
ringo = new RINGBUFFER<pack>(12);
int ret1 = pthread_create(&rdr,NULL,reader,(void*)NULL);
int ret2 = pthread_create(&wtr,NULL,writer,(void*)NULL);
#ifdef _unix
cout<< "unix single underscore\n";
#elif defined __unix
cout<< "unix two underscores\n";
#endif
pthread_join(wtr,NULL);
pthread_join(rdr,NULL);
cout<< "threads are done\n";
exit(0);
return 0;
}
void *reader(void *param){
pack myPack;
while(true)
{
for(int i=0;i<10000;i++){int k=0;k=i;k++;i=k;i--;}
if( ringo->Pop(&myPack) )
{
cout<< myPack.msg;
}
}
}
void *writer(void *param){
pack myPack;
while(true){
strcpy(myPack.msg,"hello reader!\n");
ringo->Push(&myPack);
}
}
my class header ('ringbuffer.h'):
#include<stdlib.h>
using namespace std;
#ifndef __ring_buffer_h__
#define __ring_buffer_h__
#define RINGBUFFER_DEFAULT_SIZE 8
template <class T>
class RINGBUFFER
{
private:
unsigned int top;
unsigned int bottom;
unsigned int size;
unsigned int count;
void *items;
public:
RINGBUFFER();
RINGBUFFER(unsigned int size);
~RINGBUFFER();
bool Push(T *value);
bool Pop(T *value);
};
#endif
my class definitions ('ringbuffer.CPP'):
#include "ringbuffer.h"
template<class T>
RINGBUFFER<T>::RINGBUFFER()
{
top = bottom = 0;
size = RINGBUFFER_DEFAULT_SIZE;
count = 0;
items = malloc((size+1)*sizeof(T));
}
template<class T>
RINGBUFFER<T>::RINGBUFFER(unsigned int _size)
{
top = bottom = 0;
size = _size;
count = 0;
items = malloc(size*sizeof(T));
}
template<class T>
RINGBUFFER<T>::~RINGBUFFER()
{
free(items);
}
template<class T>
bool RINGBUFFER<T>::Push(T *value)
{
if( count<size )
{
memcpy(&(((T*)items)[bottom]),value,sizeof(T));
bottom = (bottom+1)%size;
count++;
return true;
}
return false;
}
template<class T>
bool RINGBUFFER<T>::Pop(T *value)
{
if( count>0 )
{
memcpy(value,&(((T*)items)[top]),sizeof(T));
top = (top+1)%size;
count--;
return true;
}
return false;
}
To compile, I've been trying to use:
g++ ringbuffer.CPP ringbuftest.cpp -lpthread -o ringbuffertest.o
and I get the errors:
/tmp/ccj8RqhY.o: In function `main':
ringbuftest.cpp:(.text+0x21): undefined reference to `RINGBUFFER<pack>::RINGBUFFER(unsigned int)'
/tmp/ccj8RqhY.o: In function `reader(void*)':
ringbuftest.cpp:(.text+0x157): undefined reference to `RINGBUFFER<pack>::Pop(pack*)'
/tmp/ccj8RqhY.o: In function `writer(void*)':
ringbuftest.cpp:(.text+0x1db): undefined reference to `RINGBUFFER<pack>::Push(pack*)'
collect2: error: ld returned 1 exit status
I'm guessing I'm doing something wrong with g++ because I keep hitting this problem in different projects, or maybe I'm using templates wrong.(?)
How can I resolve this error?
Edit:
I should mention that this compiles perfectly if I instead paste the member definitions into the header file and exclude the .CPP from the g++ command.

You need to move the entire definition of RINGBUFFER<T> from ringbuffer.cpp to ringbuffer.h so that it's visible when ringbuftest.cpp is being compiled.

Related

Not all of my constructors are being imported?

I'm making a heap class to be importable with heap.h and my constructors including bool types do not work, yet every other constructor and function imported works.
Here is what's in heap.h:
#ifndef __HEAP_INCLUDED__
#define __HEAP_INCLUDED__
#include <iostream>
#include <vector>
using namespace std;
class heap{
int capacity;
bool isMinHeap; //1 is min heap -- ascending order
vector<int> * content;
public:
heap();
heap(bool t);
heap(vector<int> * input);
heap(vector<int> * input, bool t);
void print();
void prettyPrint();
int parent(int i);
int leftChild(int i);
int rightChild(int i);
int size();
int getMax();
void insert(int data);
void heapifyDown(int index);
void heapifyUp(int index);
int invalidChild(int index);
int deleteMax();
int deleteMin();
bool minDir();
int at(int index);
};
vector<int> * heapSort(vector<int> * input);
void swap(vector<int> * vec, int a, int b);
#endif
Here are the defined constructors in heap.cpp. Note, all constructors work fine when I add a main to this file to test stuff:
class heap{
vector<int> * content;
int capacity = 256;
bool isMinHeap; //1 is min heap -- ascending order
public:
heap(){
content = new vector<int>;
isMinHeap = 0;
}
heap(bool t){
content = new vector<int>;
isMinHeap = t;
}
heap(vector<int> * input){
content = input;
isMinHeap = true;
for(int i = content->size()/2; i >= 0; i--){
heapifyDown(i);
}
}
heap(vector<int> * input, bool t){
content = input;
isMinHeap = t;
for(int i = content->size()/2; i >= 0; i--){
heapifyDown(i);
}
}
//other functions below
}
The constructors with bool do not work in main.cpp, which has #include "heap.h" at the top. The files are all in the same directory and I am compiling with this command: g++ heap.cpp main.cpp -o main. Why do two of my constructors not work?
The error I see is
/usr/bin/ld: /tmp/ccwomODk.o: in function `main':
main.cpp:(.text+0x4e2): undefined reference to `heap::heap(bool)'
collect2: error: ld returned 1 exit status
-Wall does not elaborate on the issue. I'm pretty sure the issue is with my linking somewhere because the constructors work inside of heap.cpp when I use them in there.
What you are doing with the class in the .cpp file is wrong. You are not allowed to define the class twice. There must only be one class heap { /*...*/ }; in the program (but it may be included in multiple .cpp files). Otherwise the one-definition-rule (ODR) is violated and the program has undefined behavior.
So remove everything you are showing from heap.cpp.
To define the constructors of heap in the heap.cpp file, you need to use this syntax:
#include "heap.h"
heap::heap() {
/*...*/
}
heap::heap(bool t) {
/*...*/
}
//...
and so on. The other member functions must be defined in a similar way, e.g.:
void heap::print() {
/*...*/
}
Furthermore, if you want to have a default member initializer as in
int capacity = 256;
add it in the declaration in the .h file instead.
I also want to add that having a pointer-to-std::vector as member is almost surely a wrong approach as well, but out-of-scope for the question.
When you declare a program element such as a class, function, or
variable, its name can only be "seen" and used in certain parts of
your program. The context in which a name is visible is called its
scope. For example, if you declare a variable x within a function, x
is only visible within that function body.
It seems you broke ODR rule so bad. Your class members including constructors has no body declared in the source file(heap.cpp).
Use '::' to make class members have a body:
//heap.cpp
"heap.h"
heap::heap()
{
}
heap:heap(vector<int> * input, bool t)
{
}
int heap::parent(int i)
{
return i;
}
// this is how you create a body for function that are class members
// the same should be done for all other functions

Not sure what is causing error c2600 in code

I have looked at other forum posts and I am still confused. I am very new to coding so a simple answer would be appreciated. I am trying to create a simple program that uses sets and gets to set the player's attributes and then gets them with functions. However, whenever I call the functions I get the error.
Here is my .h file:
#pragma once
#include <iostream>
#include <dos.h>
#include <string>
#include <sstream>
using namespace std;
class Player
{
private:
string name;
int health;
int strength;
int stamina;
int experience;
bool passive;
public:
string GetName();
string SetName(string tName);
int GetHealth();
int SetHealth(int tHealth);
int GetStrength();
int SetStrength(int tStrength);
int GetStamina();
int SetStamina(int tStamina);
int GetExperience();
int SetExperience(int tExperience);
bool GetPassive();
bool SetPassive(bool tPassive);
};
And here is my 1st then 2nd cpp file:
#include <iostream>
#include <iostream>
#include <dos.h>
#include <string>
#include <sstream>
#include "C:\\Users\\Ryan Bell\\Desktop\\School\\2nd Year\\Quarter 1\\Programming\\Week 1\\PlayerClass\\PlayerClass\\PlayerClass.h"
Player::Player()
{
name = "";
health = 100;
strength = 30;
stamina = 100;
experience = 20;
passive = false;
}
string Player::GetName()
{
return name;
}
string Player::SetName(string tName)
{
name = tName;
return "Ok";
}
int Player::GetHealth()
{
return health;
}
int Player::SetHealth(int tHealth)
{
health = tHealth;
}
int Player::GetStrength()
{
return strength;
}
int Player::SetStrength(int tStrength)
{
strength = tStrength;
}
int Player::GetStamina()
{
return stamina;
}
int Player::SetStamina(int tStamina)
{
stamina = tStamina;
}
int Player::GetExperience()
{
return experience;
}
int Player::SetExperience(int tExperience)
{
experience = tExperience;
}
bool Player::GetPassive()
{
return passive;
}
bool Player::SetPassive(bool tPassive)
{
passive = tPassive;
}
#include <iostream>
#include <iostream>
#include <dos.h>
#include <string>
#include <sstream>
#include "C:\\Users\\Ryan Bell\\Desktop\\School\\2nd Year\\Quarter 1\\Programming\\Week 1\\PlayerClass\\PlayerClass\\PlayerClass.h"
int main()
{
Player Player1;
Player1.SetName("Jake");
Player1.SetHealth(100);
Player1.SetStrength(30);
Player1.SetStamina(50);
Player1.SetExperience(0);
Player1.SetPassive(true);
cout << "Player " << Player1.GetName() << ".";
}
Thank you for your time and help!
I don't see a Player Constructor declared:
// I see the Player Constructor definition here.
Player::Player()
{
.....
But this method is not declared in the class.
class Player
{
private:
.....
public:
Player(); // Add this line.
string GetName();
PS. Your code should compile and "probably" runs but is not good. If you can show it working, you can take it to Code Review and get them to give you advice on how to make it better (and some obvious errors corrected).
The compilation of your code gives:
2.cpp: In member function ‘int Player::SetStamina(int)’:
2.cpp:18:1: warning: no return statement in function returning non-void [-Wreturn-type]
18 | }
| ^
2.cpp: In member function ‘int Player::SetExperience(int)’:
2.cpp:28:1: warning: no return statement in function returning non-void [-Wreturn-type]
28 | }
| ^
2.cpp: In member function ‘bool Player::SetPassive(bool)’:
2.cpp:38:1: warning: no return statement in function returning non-void [-Wreturn-type]
38 | }
These can be fixed by turning all setters as functions returning void, e.g:
void Player::SetStamina(int tStamina)
Do it both in *.h and player.cpp.
After fixing this, we bump onto linker errors:
/usr/bin/ld: /tmp/ccQk0cvm.o: in function `main':
main.cpp:(.text+0x6c): undefined reference to `Player::SetName(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
/usr/bin/ld: main.cpp:(.text+0xa7): undefined reference to `Player::SetHealth(int)'
/usr/bin/ld: main.cpp:(.text+0xb8): undefined reference to `Player::SetStrength(int)'
/usr/bin/ld: main.cpp:(.text+0x11a): undefined reference to `Player::GetName[abi:cxx11]()'
collect2: error: ld returned 1 exit status
This means that you forgot to define Player::GetName, Player::SetStrength(int), and 2 other methods.
This leads us to the simplest solution (for now): modify the public section of your class so that it implements all functions:
public:
std::string GetName() const { return name; }
void SetName(string tName) { name = tName; }
int GetHealth() const { return health; }
void SetHealth(int tHealth) { health = tHealth; }
int GetStrength() const { return strength; }
void SetStrength(int tStrength) { strength = tStrength; }
int GetStamina() const { return stamina; }
void SetStamina(int tStamina) { stamina = tStamina; }
int GetExperience() const { return experience; }
void SetExperience(int tExperience) { experience = tExperience; }
bool GetPassive() const { return passive; }
void SetPassive(bool tPassive) { passive = tPassive; }
and don't use a separate source file for the class member definitions.
Alternatively, you can keep the file, but then you must add all missing function definitions in it.
Notice that I declared all getters as const member functions. Believe me, this is how they should be defined.

How can I get rid of the <error-type> type that is appearing in my method template? Both the input to the method and the class are templates

I am getting the error
declaration is incompatible with "void spectrogram<T>::update(<error-type> x)
I don't see any difference between the declaration and the definition of the method, not sure why it is complaining about just this one definition and not the constructor or destructor.
Here is vComplex.hpp
#ifndef VCOMPLEX_H
#define VCOMPLEX_H
template <class T>
class vComplex {
public:
T* realp;
T* imagp;
int length; // for bookkeeping
vComplex(void) { }
vComplex (T* I, T* Q, int len) {
realp = I;
imagp = Q;
length = len;
}
~vComplex(void) {
free(realp);
free(imagp);
}
void put(T* I, T*Q, int len) {
realp = I;
imagp = Q;
length = len;
}
};
#endif
the function declaration for update in spectrogram.hpp, with other members removed:
#ifndef SPECTROGRAM_H
#define SPECTROGRAM_H
template <typename T>
class spectrogram {
public:
void update(vComplex<T> x);
};
#endif
and the function signature (and includes) for update in spectrogram.cpp:
#include <stdio.h>
#include <math.h>
#include "spectrogram.hpp"
#include "vComplex.hpp"
template <typename T>
void spectrogram<T>::update(vComplex<T> x) {
//do stuff
}
In VS 2017, I get the red underline under update and everything inside of it breaks basically. VS is saying T is undefined which I'm assuming is caused by the overall error. I have to use dynamically allocated pointers, I don't have the option of using other types or containers.

Include issue: 'multiple definition', 'first defined here'

I have three files:
main.cpp
MyClass.cpp
MyClass.hpp
I have a library header file, "testLib.hpp", that I want to include in MyClass.hpp so that I can have one of testLib's objects be a class attribute.
I include MyClass.hpp in MyClass.cpp and in main.cpp. When attempting to compile the project, I get the following errors
MyClass.cpp multiple definition of 'testLib::testLib::function1()
obj/Release/main.o:main.cpp first defined here
MyClass.cpp multiple definition of 'testLib::testLib::function2()
obj/Release/main.o:main.cpp first defined here
and so on.
Both main.cpp and MyClass.cpp include MyClass.hpp (which includes testLib.hpp). Judging by the error, it looks like MyClass.cpp is attempting to include the library functions after they've already been included by main.cpp. However, I have include guards present in MyClass.hpp so I don't understand how it's trying to include MyClass.hpp twice.
Here's the code:
MyClass.hpp
#ifndef THIS_HEADER_H
#define THIS_HEADER_H
#include <stdint.h>
#include <iostream>
#include "testLib/testLib.hpp"
class MyClass
{
public:
void test();
int foo;
private:
uint32_t bar;
//I want to include an object from the library as part of this class
//TestLib::Device device;
};
#endif
MyClass.cpp
#include <stdio.h>
#include "MyClass.hpp"
void MyClass::test()
{
}
main.cpp
#include <iostream>
#include "MyClass.hpp"
using namespace std;
int main()
{
cout << "Hello world!" << endl;
return 0;
}
Any help would be greatly appreciated!
EDIT
I tried to hide the actual filenames to make the question more general and clear, but it seems like the problem might be resulting from 'testLib.hpp', which I did not write. That file is actually the following "sweep.hpp" file. I got the 'multiple definition of/first defined here' errors for each of the public functions in this file:
sweep.hpp
#ifndef SWEEP_DC649F4E94D3_HPP
#define SWEEP_DC649F4E94D3_HPP
/*
* C++ Wrapper around the low-level primitives.
* Automatically handles resource management.
*
* sweep::sweep - device to interact with
* sweep::scan - a full scan returned by the device
* sweep::sample - a single sample in a full scan
*
* On error sweep::device_error gets thrown.
*/
#include <cstdint>
#include <memory>
#include <stdexcept>
#include <vector>
#include <sweep/sweep.h>
namespace sweep {
// Error reporting
struct device_error final : std::runtime_error {
using base = std::runtime_error;
using base::base;
};
// Interface
struct sample {
const std::int32_t angle;
const std::int32_t distance;
const std::int32_t signal_strength;
};
struct scan {
std::vector<sample> samples;
};
class sweep {
public:
sweep(const char* port);
sweep(const char* port, std::int32_t bitrate);
void start_scanning();
void stop_scanning();
bool get_motor_ready();
std::int32_t get_motor_speed();
void set_motor_speed(std::int32_t speed);
std::int32_t get_sample_rate();
void set_sample_rate(std::int32_t speed);
scan get_scan();
void reset();
private:
std::unique_ptr<::sweep_device, decltype(&::sweep_device_destruct)> device;
};
// Implementation
namespace detail {
struct error_to_exception {
operator ::sweep_error_s*() { return &error; }
~error_to_exception() noexcept(false) {
if (error) {
device_error e{::sweep_error_message(error)};
::sweep_error_destruct(error);
throw e;
}
}
::sweep_error_s error = nullptr;
};
}
sweep::sweep(const char* port)
: device{::sweep_device_construct_simple(port, detail::error_to_exception{}), &::sweep_device_destruct} {}
sweep::sweep(const char* port, std::int32_t bitrate)
: device{::sweep_device_construct(port, bitrate, detail::error_to_exception{}), &::sweep_device_destruct} {}
void sweep::start_scanning() { ::sweep_device_start_scanning(device.get(), detail::error_to_exception{}); }
void sweep::stop_scanning() { ::sweep_device_stop_scanning(device.get(), detail::error_to_exception{}); }
bool sweep::get_motor_ready() { return ::sweep_device_get_motor_ready(device.get(), detail::error_to_exception{}); }
std::int32_t sweep::get_motor_speed() { return ::sweep_device_get_motor_speed(device.get(), detail::error_to_exception{}); }
void sweep::set_motor_speed(std::int32_t speed) {
::sweep_device_set_motor_speed(device.get(), speed, detail::error_to_exception{});
}
std::int32_t sweep::get_sample_rate() { return ::sweep_device_get_sample_rate(device.get(), detail::error_to_exception{}); }
void sweep::set_sample_rate(std::int32_t rate) {
::sweep_device_set_sample_rate(device.get(), rate, detail::error_to_exception{});
}
scan sweep::get_scan() {
using scan_owner = std::unique_ptr<::sweep_scan, decltype(&::sweep_scan_destruct)>;
scan_owner releasing_scan{::sweep_device_get_scan(device.get(), detail::error_to_exception{}), &::sweep_scan_destruct};
auto num_samples = ::sweep_scan_get_number_of_samples(releasing_scan.get());
scan result;
result.samples.reserve(num_samples);
for (std::int32_t n = 0; n < num_samples; ++n) {
auto angle = ::sweep_scan_get_angle(releasing_scan.get(), n);
auto distance = ::sweep_scan_get_distance(releasing_scan.get(), n);
auto signal = ::sweep_scan_get_signal_strength(releasing_scan.get(), n);
result.samples.push_back(sample{angle, distance, signal});
}
return result;
}
void sweep::reset() { ::sweep_device_reset(device.get(), detail::error_to_exception{}); }
} // ns
#endif
A simplified version of your problem:
buggy.hpp
int function() { return 0; }
main.cpp
#include "buggy.hpp"
int main() { return 0; }
other.cpp
#include "buggy.hpp"
The problem is that buggy.hpp is defining function, not just declaring. Once the header inclusion is expanded, that means function is declared in both main.cpp and other.cpp - and that is not allowed.
The fix is to declare function as inline which allows the function to be declared in multiple translation units.
inline int function() { return 0; }
In fact, allowing multiple definitions is the only meaning of inline to the C++ standard. Compilers may treat it as a hint that the function body may be expanded inline. Good ones won't; they are better at making that sort of decision that programmers).

"undefined reference" to a template class function

I am writing a template class for an array of objects, call it arrayobjclass, which holds pointers to other objects, specifically to other arrays in my implementation. The arrays are implemented as objects as well, call them arrayclass.
Looking for compilation ready with minimal changes.
when I try to test my classes with the following line,
g++ main.cpp arrayclass.cpp arrayobjclass.cpp -o arrayobj
I get the following error:
/tmp/ccEpROXj.o(.text+0x17c): In function `main':
: undefined reference to `arrayobjclass<arrayclass, int>::arrayobjclass(int)'
/tmp/ccEpROXj.o(.text+0x1dc): In function `main':
: undefined reference to `arrayobjclass<arrayclass, int>::addelem(arrayclass*)'
collect2: ld returned 1 exit status
I really can't understand what is wrong. any help would be appreciated. the short relevant part of the code is below if it helps. THANKS IN ADVANCE!
This is what i have in main:
#include "arrayclass.h"
#include "arrayobjclass.h"
#include <iostream>
// 5 arrays of 10 maxsize each
#define MAXSIZE_array 10
#define NUMB_objs 5
using namespace std;
int main () {
//create a simple array as an arrayclass object
arrayclass * numbers1 = new arrayclass (MAXSIZE_array);
//array of objects to hold pointers to simple arrays as created above
arrayobjclass<arrayclass,int> * myobjs = new arrayobjclass<arrayclass,int> (NUMB_objs);
//fill up the simple array
int i;
for (i=0; i<10; i++) {
numbers1->addelem(i);
}
//add a pointer to the simple array in my array of objects
myobjs->addelem(numbers1);
}
//arrayobjclass.h
//declarations of an array of pointers to objects
template <class obj, class key>
class arrayobjclass {
private:
//obj * arrayptr;
obj * objarray [];
int maxsize;
int totalelem;
public:
arrayobjclass(int);
bool addelem(obj *);
};
//arrayobjclass.cpp
//implementation of arrayobjclass, array of pointers to objects
#include "arrayobjclass.h"
#include "arrayclass.h"
template <class obj,class key>
arrayobjclass<obj,key>::arrayobjclass (int size){
maxsize=size;
objarray = new obj[maxsize];
totalelem = 0;
}
template <class obj, class key>
bool arrayobjclass<obj,key>::addelem (obj * newobj) {
if (totalelem < maxsize ) {
objarray[totalelem] = newobj;
totalelem ++;
return true;
}
return false;
}
//arrayclass.h
class arrayclass {
private:
int * arrayptr;
int maxsize;
int totalelem;
public:
arrayclass(int);
bool addelem(int);
};
//arrayclass.cpp
#include "arrayclass.h"
arrayclass::arrayclass (int size){
maxsize=size;
arrayptr = new int[maxsize];
totalelem = 0;
}
bool arrayclass::addelem (int addval) {
if (totalelem < maxsize ) {
arrayptr[totalelem] = addval;
totalelem ++;
return true;
}
return false;
}
You can't put template declarations in .cpp files like that. Template declarations and implementation need to be visible in the same translation unit. Put template implementations in headers that you #include directly.
Define your function templates in the header. Compiler needs to see them.
Cheers & hth.,
Because templates are compiled when required, this forces a
restriction for multi-file projects: the implementation (definition)
of a template class or function must be in the same file as its
declaration. That means that we cannot separate the interface in a
separate header file, and that we must include both interface and
implementation in any file that uses the templates.
From http://www.cplusplus.com/doc/tutorial/templates/
For anyone passing by
you can also #include the implementation files in main
in main:
#include "arrayobjclass.h"
#include "arrayclass.h"
#include "arrayobjclass.cpp"
#include "arrayclass.cpp"