I have an Abstractqueue and I want to inherit it's members to another child class. When I try to create the child object in my main file I keep getting an undefined reference to `AbstractQueue::AbstractQueue()'
enter code here
#ifndef ABSTRACT_QUEUE_H
#define ABSTRACT_QUEUE_H
#include <iostream>
template <class Type>
class AbstractQueue
{
protected:
Type *items;
int front;
int back;
int capacity;
int count;
private:
// data goes here
public:
AbstractQueue(int s);
AbstractQueue(void);
~AbstractQueue(void);
bool empty();
int size();
Type frontele(); //throw(exception) {}
Type dequeue(); //throw(exception) {}
void enqueue ( Type e );
};
template <class Type>
AbstractQueue<Type>::AbstractQueue(int s){
items = new Type[s];
front = 0;
back = 0;
capacity = s;
count = 0;
std::cout << "made the abstract queue!" << std::endl;
}
template <class Type>
AbstractQueue<Type>::~AbstractQueue() {
delete[] items;
std::cout << "destructor called" << std::endl;
}
#endif
IncrementalQueue.h
#ifndef _INCREMENTALQUEUE_H
#define _INCREMENTALQUEUE_H
#include "Queue.h"
//#define SIZE = 10
#include <iostream>
template <class Type>
class IncrementalQueue : public AbstractQueue<Type>{
public:
//AbstractQueue(void);
//~AbstractQueue(void);
IncrementalQueue(int s);
bool empty();
int size();
Type frontele(); //throw(exception) {}
Type dequeue(); //throw(exception) {}
void enqueue ( Type e );
//~IncrementalQueue(void);
//AbstractQueue(void);
//AbstractQueue(int size);
//bool empty(void) ;
/*if (count == 0) {
return true;
}
else {
return false;
}*/
//int size(void);
//Type front throw(exception) {}
//Type dequeue(); //throw(exception) {}
//void enqueue ( Type e ) ;
//IncrementalQueue(int size);
};
template <class Type>
IncrementalQueue<Type>::IncrementalQueue(int s){
this->items = new Type[50];
this->front = 0;
this->back = 0;
this->capacity = 50;
this->count = 0;
std::cout << "made the incremental queue!" << std::endl;
}
#endif
main.cpp
#include "Queue.h"
#include "IncrementalQueue.h"
int main(){
IncrementalQueue<int> incqueue(50);
return 0;
}
I'm a little rusty with templates so I've been struggling at it for a couple of hours. does anybody have any clues on where my code can be failing?
IncrementalQueue::IncrementalQueue() constructor is calling the AbstractQueue::AbstractQueue() constructor and you have not defined it.
To make it compile you can just say AbstractQueue() = default; to have it generated by the compiler, if you are using C++11 or later, but that will not necessarily be correct (see the comments).
As it always happens with templates, you either need to put AbstractQueue::AbstractQueue() implementation (function body) to its header, or, if you know in advance all its possible template parameters, explicitly instantiate this function in cpp-file:
template class AbstractQueue<NeededType>;
In your case, it's impossible to know all possible template args in advance, so you need to put your function body to the header. That's the price of separate unit compilation.
Related
Hi i am trying to implement an array based stack (in c++) but i have been stuck in it for a while. whenever i try to make an object in my source file, compiler generates the error "cannot declare variable ‘list’ to be of abstract type ‘aStack’
aStack list(5);" even though i aStack class is inheriting from ADT abs_stack. here's my code
enter code here
// question #1.
// ADT for stack.
template <class type>
class abs_stack {
public:
virtual void initialize_stack() = 0; // starts the stack.
virtual bool isEmpty() = 0; // checks whether stack is empty or not.
virtual bool isFull() = 0; // checks whether stack is full or not.
virtual void push(type n) = 0; //
virtual void pop() = 0;
virtual type top() = 0;
};
// declaring array based stack.
template <typename t>
//template <typename E>
// class AStack: public Stack<E>
class aStack : public abs_stack<t> {
private:
t *grid; // stack.
int max_stack_size;
int top_element; // points to the top of the stack.
void stack_copy(aStack<t> ©); // used in copy contructor.
public:
aStack(int size); // paratmeterized constructor.
~aStack(); // destructor.
aStack(const aStack <t> &); // copy constructor.
const aStack<t> & operator =
(const aStack<t> &originalStack); // overloaded assignment operator.
//------------------------------------->
bool isEmpty() const;
bool isFull() const;
void pop();
void push(const t &newElem);
t top() const;
void initialize_stack();
};
enter code here
#ifndef H_stack
#define H_Stack
#include <iostream>
#include <cassert>
#include "stack.h"
using namespace std;
// stack methods' implementation.
template <class x> const aStack<x>& aStack<x>::operator=
(const aStack<x>& otherStack)
{
if (this != &otherStack) //avoid self-copy
copyStack(otherStack);
return *this;
}// end of overloaded assignment operator.
template <typename x>
void aStack<x> :: pop() {
if (!isEmpty()) {
top_element--; // decreases the position # of the top element.
}
else {
cout << "Error! Stack is already. Cannot remove anything." << endl;
}
} // end of pop()
template <typename x>
void aStack<x> :: push(const x &newElem) {
if (!isFull()) {
grid[top_element] = newElem; // places new element on the top
top_element++;
}
else {
cout << "No space available." << endl;
}
} // end of push
template <typename x>
x aStack<x> :: top() const {
assert(top_element != 0); // checks whether stack exists or not.
return grid[top_element - 1];
}
template <typename x>
void aStack<x>::initialize_stack() {
top_element = 0;
}
template <typename x>
bool aStack<x> :: isEmpty() const {
return (max_stack_size == 0);
}
template <typename x>
bool aStack<x> :: isFull() const {
return (top_element == max_stack_size);
}
template <typename x>
aStack<x> :: aStack(int size) {
if ( size <= 0) {
cout << "Error! Stack size can" <<
" never be lesser than/equal to 0." << endl
<< "Generating stack of size 10" << endl;
max_stack_size = 10;
}
else {
max_stack_size = size;
}
top_element = 0;
grid = new x[max_stack_size];
} // end of parameterized contructor.
template <typename x>
aStack<x> :: ~aStack() {
delete []grid;
grid = NULL;
max_stack_size = 0;
} // end of destructor.
template <typename x>
aStack<x> :: aStack(const aStack<x> &firstStack) {
grid = NULL;
stack_copy(firstStack);
} // end of copy contructor.
template <typename x>
void aStack<x> :: stack_copy(aStack<x> ©) {
delete []grid;
grid = NULL;
max_stack_size = copy.max_stack.size;
top_element = copy.top.element;
grid = new x[max_stack_size];
// generating deep copy of the original stack.
for (int i =0; i < max_stack_size; i ++)
grid[i] = copy.grid[i];
} // end of stack copy.
#endif
#include <iostream>
#include "stack.h"
using namespace std;
//--------- source file-->
int main() {
aStack<int> list(5);
return 0;
}
The error implies that your class aStack is an abstract class, i.e. has at least one pure virtual method and therefore cannot be instantiated. That means that some of your aStack methods failed to participate in virtual overriding as a result of signature mismatch.
Notice that cv-qualifiers and ref-qualifires affect the parameter type and change the signature:
void f(int x)
void f(const int& x)
are considered different functions. Same goes for member functions cv-qualifiers, so only pop and initialize_stack retain original signature in your code.
I am new to the c++ language and need help with the problem below. Presently, I am trying to get my head around "templates" and "function pointers". The following template class, Queue, compiles when written into a single .cpp file:
template <typename T> class Queue
{
public:
Queue()
{
m_add = m_remove = 0;
}
void enque(T *c)
{
m_array[m_add] = c;
m_add = (m_add + 1) % SIZE;
}
T *deque()
{
int temp = m_remove;
m_remove = (m_remove + 1) % SIZE;
return m_array[temp];
}
private:
enum
{
SIZE = 8
};
T *m_array[SIZE];
int m_add, m_remove;
};
However, when I separate this code into the .h and .cpp files (as below), I get errors where I am defining the function pointer in the .cpp file; near the line:
template<typename T>
T (Queue<T>::*deque)() {
Queue.h:
#ifndef QUEUE_H_
#define QUEUE_H_
template<typename T>
class Queue {
enum {
SIZE = 8
};
T *m_array[SIZE];
int m_add, m_remove;
public:
Queue();
virtual ~Queue();
void enque(T *c);
T *deque();
};
#endif /* QUEUE_H_ */
Queue.cpp:
#include "Queue.h"
template<typename T>
Queue<T>::Queue() {
m_add = m_remove = 0;
}
template<typename T>
Queue<T>::~Queue() {
}
template<typename T>
void Queue<T>::enque(T *c) {
m_array[m_add] = c;
m_add = (m_add + 1) % SIZE;
}
template<typename T>
T (Queue<T>::*deque)() {
int temp = m_remove;
m_remove = (m_remove + 1) % SIZE;
return m_array[temp];
}
I am hoping that one of you c++ experts could help me understand how to define the function pointer < T *deque() > Thank you in advance for your help.
Your implementation doesn't match your declaration (obviously). Your function is declared as:
template<class T>
class Queue
{
//... other members
T* deque();
};
Outside of the class body, that becomes:
template<class T>
T* Queue<T>::deque()
That said, you need to read this: "Why can templates only be implemented in the header file". It will explain why it was very likely a mistake that you moved your template implementation to a cpp file from where it belongs: the header.
I have a program that uses something I made called "SortableVector," with a parent called SimpleVector. The Simple Vector is fine, and so is most of SortableVector, but the problem is the sort function in SortableVector. It sorts numbers just fine, but I can't get it to sort strings. Here's what I originally had:
template <class T>
void SortableVector<T>::sort()
{
T temp = 0;
for(int i = 0; i < this->size(); i++)
{
for (int count = i+1; count < this->size(); count++)
{
if(this->operator[](0) == int)
{
if (this->operator[](count) < this->operator[](i))
{
temp = this->operator[](count);
this->operator[](count) = this->operator[](i);
this->operator[](i) = temp;
count = i+1;
}
}
}
}
}
Then I tried to use the sort(begin, end) function, but that didn't work either:
template <class T>
void SortableVector<T>::sort()
{
sort(this->operator[].begin(), this->operator[].end();
}
EDIT: To help people understand the problem, here's the whole file:
#ifndef SORTABLEVECTOR_H
#define SORTABLEVECTOR_H
using namespace std;
#include "SimpleVector.h"
#include <algorithm>
#include <fstream>
#include <string>
template <class T>
class SortableVector : public SimpleVector<T>
{
public:
SortableVector(int s) : SimpleVector<T>(s)
{}
SortableVector(SortableVector &);
SortableVector(SimpleVector<T> &obj):
SimpleVector<T>(obj)
{}
void sort();
};
template <class T>
SortableVector<T>::SortableVector(SortableVector &obj):SimpleVector<T>(obj)
{
}
template <class T>
void SortableVector<T>::sort()
{
std::sort(this->operator[].begin(), this->operator[].end());
T temp = 0;
for(int i = 0; i < this->size(); i++)
{
for (int count = i+1; count < this->size(); count++)
{
if(this->operator[](0) == int)
{
if (this->operator[](count) < this->operator[](i))
{
temp = this->operator[](count);
this->operator[](count) = this->operator[](i);
this->operator[](i) = temp;
count = i+1;
}
}
}
}
}
#endif
And this is SimpleVector:
// SimpleVector.h
#ifndef SIMPLEVECTOR_H
#define SIMPLEVECTOR_H
#include <iostream>
#include <cstdlib>
using namespace std;
template <class T>
class SimpleVector
{
private:
T *aptr;
int arraySize;
void subError(); // Handles subscripts out of range
public:
SimpleVector() // Default constructor
{ aptr = 0; arraySize = 0;}
SimpleVector(int); // Constructor
SimpleVector(const SimpleVector &); // Copy constructor
~SimpleVector(); // Destructor
int size() { return arraySize; }
T &operator[](int); // Overloaded [] operator
void print() const; // outputs the array elements
void push_back(T); // newly added function (implemention needed)
T pop_back(); // newly added function (implemention needed)
};
//****************************************************************
// Constructor for SimpleVector class *
// Sets the size of the array and allocates memory for it. *
//****************************************************************
template <class T>
SimpleVector<T>::SimpleVector(int s)
{
arraySize = s;
aptr = new T [s];
}
//*********************************************
// Copy Constructor for SimpleVector class *
//*********************************************
template <class T>
SimpleVector<T>::SimpleVector(const SimpleVector &obj)
{
arraySize = obj.arraySize;
aptr = new T [arraySize];
for(int count = 0; count < arraySize; count++)
*(aptr + count) = *(obj.aptr + count);
}
// *************************************
// Destructor for SimpleVector class *
// *************************************
template <class T>
SimpleVector<T>::~SimpleVector()
{
if (arraySize > 0)
delete [] aptr;
}
//************************************************************
// SubError function *
// Displays an error message and terminates the program when *
// a subscript is out of range. *
//************************************************************
template <class T>
void SimpleVector<T>::subError()
{
cout << "ERROR: Subscript out of range.\n";
exit(0);
}
//***********************************************************
// Overloaded [] operator *
// This function returns a reference to the element *
// in the array indexed by the subscript. *
//***********************************************************
template <class T>
T &SimpleVector<T>::operator[](int sub)
{
if (sub < 0 || sub >= arraySize)
subError();
return aptr[sub];
}
//********************************************************
// prints all the entries is the array. *
//********************************************************
template <class T>
void SimpleVector<T>::print( ) const
{
for (int k = 0; k < arraySize; k++ )
cout << aptr[k] << " ";
cout << endl;
}
//***************************************************************
// (1) push_back(T val) *
// The push_back function pushes its argument onto the back *
// Of the vector. *
//***************************************************************
template <class T>
void SimpleVector<T>::push_back(T val)
{
aptr[arraySize] = val;
arraySize++;
}
// *****************************************************
// (2) pop_back() *
// The pop_back function removes the last element *
// Of the vector. It also returns that value. *
// *****************************************************
template <class T>
T SimpleVector<T>::pop_back()
{
arraySize--;
T temp = aptr[arraySize];
return temp;
}
#endif
The SimpleVector was provided by the instructor.
You can do without the repeated this-> 99% of the time
You can just invoke operators, instead of invoking them as functions
You can just use std::sort from <algorithm>
Imagining some of the code you didn't show:
#include <vector>
#include <algorithm>
template <typename T>
struct SimpleVector {
std::vector<T> data;
virtual ~SimpleVector() {}
};
template <typename T>
struct SortableVector : public SimpleVector<T> {
void sort() {
std::sort(this->data.begin(), this->data.end());
}
};
#include <iostream>
int main()
{
SortableVector<std::string> sv;
sv.data = {"one","two","three","four"};
sv.sort();
for(auto& s : sv.data)
std::cout << s << ' ';
}
DISCLAIMER This seems a very non-c++ way to design classes. Algorithms and containers are traditionally separated, for good reason. The exception being that member functions sometimes perform operations in more optimal ways (e.g. std::set<>::find instead of std::find)
It should be std::sort(aptr, aptr + arraySize);. Also you should check arraySize > 0 before doing this, if you're intending to catch errors like that instead of having undefined behaviour.
begin and end aren't magic; they rely on the object either being an array (not a pointer), or the object implementing functions .begin() and .end() that return iterators.
You could even define those functions yourself, e.g. SimpleVector<T>::begin() { return aptr; } etc. , but maybe this is not a good idea as it bypasses your bounds-checking. You'd have to actually write an iterator class instead of returning a pointer, which is more trouble than you're ready for :)
NB. Everywhere you write this->operator[](foo), it would be clearer to write (*this)[foo]
I'm pretty new to C++ and this site so there are bound to be errors. When I try to compile my code I get errors like error: missing template argument before 'b'. I've been searching the world for answers for hours and it has led me here.
My assignment is to implement a templated class Collection that stores a collection of
Objects using an array, along
with the current size of the collection.
#include <iostream>
#include "collection.h"
using namespace std; v
int main(int argc, char* argv[])
{
collection b; //<----error missing template argument before 'b'
return 0;
}
#ifndef COLLECTION_H
#define COLLECTION_H
#include <iostream>
template <typename obj>
class collection
{
public:
collection();
bool isEmpty() const;
void makeEmpty();
void insert(obj val);
void remove(obj val);
bool contains(obj val) const;
private:
size_t size;
obj* col[];
};
#endif
#include "collection.h"
template <typename obj>
collection<obj>::collection() :size(10)
{
col = new obj*[size];
}
template <typename obj>
bool collection<obj>::isEmpty() const
{
for(size_t k = 0; k < size; k++)
{
if(col[k] != NULL)
return false;
}
return true;
}
template <typename obj>
void collection<obj>::makeEmpty()
{
for(size_t k = 0; k < size; k++)
{
col[k] = NULL;
}
}
template <typename obj>
void collection<obj>::insert(obj val)
{
int temp = 0;
for(size_t s = 0; s < size; s++)
{
if(col[s] != NULL)
temp++;
}
if(temp >= size)
{
obj* temp = new obj*[size*2];
for(size_t c = 0; c < size; c++)
temp[c] = col[c];
delete col;
col = temp;
}
else
col[temp] = val;
}
template <typename obj>
void collection<obj>::remove(obj val)
{
for(size_t x = 0; x < size; x++)
{
if (col[x] == val)
{
for(size_t y = x; y < size-1; y++)
{
col[y] = col[y+1];
}
col[size-1] = NULL;
return;
}
}
}
template <typename obj>
bool collection<obj>::contains(obj val) const
{
for(size_t z = 0; z < size; z++)
{
if(col[z] == val)
return true;
}
return false;
}
You have to say what it's a collection of.
template <class A> class collection {}
requires that you use it as
collection<int> b;
or some appropriate type. That then makes a collection of ints. You haven't told it what you want a collection of.
First : Instantiate template by type. So if you have template <typename obj> class T {...}; you should use it like
void main {
T<int> t;
T<bool> t1; // .. etc
}
You can use a template with default value for the typename parameter defined in the class template declaration
template <typename obj = int> class T {/*...*/};
void main {
T<> t;
}
but anyway you should put empty angle brackets when use it without parameter.
Second: While declaring template, place it whole in the header file. Each definition of his methods should be in the file "*.h", don't ask me why, just don't split it to the header and "cpp" file.
Hope it helps.
Well, you're missing a template argument. You can't create a collection object, that's just a template.
You can only create e.g. a collection<int> or collection<std::string>.
You need to specify the type for template, like int or some other type:
collection<int> b;
There are a large number of errors in your code. First define your template in a header file:
In collection.h put the following:
#ifndef COLLECTION_H
#define COLLECTION_H
template <typename obj>
class collection
{
public:
collection() {}
bool isEmpty() const;
void makeEmpty();
void insert(obj val);
void remove(obj val);
bool contains(obj val) const;
private:
size_t size;
obj* col[];
};
#endif
Then in a .cpp file inside a main function do the following:
collection<int> b;
Instead of int you can use a different type but the main point is that YOU NEED A TYPE to instantiate a template.
I'm having trouble passing a callback function from within a class, when calling a template function. Here's a sample code:
sortedlist.h
#ifndef _sortedlist_h
#define _sortedlist_h
#include <vector>
template <typename ElemType>
class SortedList {
public:
SortedList(int (*compare)(ElemType a, ElemType b));
~SortedList();
void push(ElemType newElem);
ElemType pop();
private:
std::vector<ElemType> v;
int (*cmp) (ElemType first, ElemType second);
void Sort();
};
template <typename ElemType>
SortedList<ElemType>::SortedList(int (*compare)(ElemType a, ElemType b)) {
cmp = compare;
}
template <typename ElemType>
SortedList<ElemType>::~SortedList() {
}
template <typename ElemType>
void SortedList<ElemType>::push(ElemType newElem) {
v.push_back(newElem);
Sort();
}
template <typename ElemType>
ElemType SortedList<ElemType>::pop() {
ElemType next = v.back();
v.pop_back();
return next;
}
template <typename ElemType>
void SortedList<ElemType>::Sort() {
for (int i=v.size()-1; i>0; i--) {
if(cmp(v[i], v[i-1]) < 0) { //compare function
ElemType temp = v[i];
v[i] = v[i-1];
v[i-1] = temp;
}
else return;
}
}
#endif
game.h
#ifndef _game_h
#define _game_h
#include <string>
#include "sortedlist.h"
class Game {
public:
Game() {};
~Game() {};
void addPlayer(std::string name, int score);
std::string getWinner();
struct Player {
std::string name;
int score;
};
//compare function
int highScore(Player one, Player two);
private:
SortedList<Player> list(highScore);
};
#endif
game.cpp
#include "game.h"
void Game::addPlayer(std::string name, int score) {
Player newEntry;
newEntry.name = name;
newEntry.score = score;
list.push(newEntry);
}
std::string Game::getWinner() {
return list.pop().name;
}
//compare function
int Game::highScore(Player one, Player two) {
if (one.score == two.score) return 0;
if (one.score > two.score) return 1;
return -1;
}
sample main:
#include <iostream>
#include "game.h"
using namespace std;
int main () {
Game pacman;
pacman.addPlayer("Beavis", 100);
pacman.addPlayer("Butthead", 200);
cout << pacman.getWinner() << endl;
}
When I compile it on XCode, I get "'highscore' is not a type" error. I also tried moving Player and highScore outside of the class with similar results. What should I do instead?
In C++ you cannot initialize class-members in-place. You need to do that in the constructor initializer list
class Game {
public:
Game():list(highScore) {};
~Game() {};
//compare function
static int highScore(Player one, Player two);
private:
SortedList<Player> list;
};
The function needs to be declared as static in the class definition as SortedList calls it without a *this pointer, like an ordinary function.
Performance is really unnecessary bad of the comparison function because you always copy the two items to be compared when passing them as arguments. Better make the comparison function's type to receive const-references and change highScore's signature appropriately
int (*compare)(ElemType const& a, ElemType const& b);