I'm supposed to implement the functionality of a stack and I was given the main.cpp file and was left to write the other files, namely StackofNodes.hpp & .h. These depend on two other files Node.hpp & .h. When I try to build the program I get errors on the main.cpp file that was given to me. This are:
obj/Debug/main.o||In function `main':|
|6|undefined reference to `StackOfNodees<int>::StackOfNodees()'|
|12|undefined reference to `StackOfNodees<int>::push(int)'|
|17|undefined reference to `StackOfNodees<int>::size() const'|
|24|undefined reference to `StackOfNodees<int>::pop()'|
main.cpp
#include <iostream> //std::cout std::cin
#include "StackOfNodees.h" //StackOfNodes
int main()
{
StackOfNodees<int> myStack; //Create an empty stack
int sizeOfStack; //int we'll use later to store the size of the stack
//push some numbers onto the stack
for(int i = 1; i <= 10; i++)
{
myStack.push( i * 5 );
}
//Store the size of the stack before popping anything
sizeOfStack = myStack.size();
std::cout << "There are " << sizeOfStack << " items on the stack" << std::endl;
//Think about why we don't use i<myStack.size()
for(int i = 0; i < sizeOfStack; i++)
{
std::cout << "Popping the top: " << myStack.pop() << std::endl;
}
/* while(!myStack.isEmpty()) is another valid way to pop all the contents of the stack */
}
StackOfNodees.hpp
#ifndef STACKOFNODEES_HPP_INCLUDED
#define STACKOFNODEES_HPP_INCLUDED
StackOfNodees::StackOfNodees()
{
m_top=nullptr;
m_size=0;
}
bool StackOfNodees::isEmpty() const
{
if (m_size==0)
{
return true;
}
return false;
}
int StackOfNodees::size() const
{
return m_size;
}
void StackOfNodees::push(int value)
{
Node* Node1 = new Node;
Node1 -> m_previous = m_top;
m_top=Node1;
Node1 -> m_value = value;
++m_size;
}
int StackOfNodees::pop()
{
// initialize
int returnval = 0;
if (!isEmpty())
{
// fetch the value from the top one
returnval = m_top -> m_value;
Node* temp = m_top;
//move m_top down to previous box.
m_top = m_top -> m_previous;
//delete the popped one
delete temp;
m_size--;
}
else
{
// you may want to throw an exception here for popping a empty stack
}
return returnval;
}
#endif // STACKOFNODEES_HPP_INCLUDED
Node.h
#ifndef NODE_H_INCLUDED
#define NODE_H_INCLUDED
template<typename T>
Node<T>::Node()
{
Node.setPrevious(nullptr);
Node.setValue();
}
//initiation of getters
template<typename T>
T Node::getValue()
{
return m_value;
}//end getValue
template<typename int>
int Node::getPrevious()
{
return m_previous;
}//end getPrevious
//initiation of setters
template<typename void>
void Node::setValue(T value)
{
m_value = value;
}//end setValue
template<typename void>
void Node::setPrevious(Node<T>* previous)
{
Node<T>* previous = m_previous;
}//end setPrevious
StackOfNodees.h
#ifndef STACKOFNODEES_H_INCLUDED
#define STACKOFNODEES_H_INCLUDED
#include "Node.h"
template<typename T>
class StackOfNodees
{
private:
Node<T>* m_top;
int m_size;
public:
StackOfNodees();
bool isEmpty() const;
int size() const;
void push(T value);
T pop();
};
#endif // STACKOFNODEES_H_INCLUDED
Any help would be much appreciated. Thanks!
You do not have methods of template class StackOfNodees defined.
You need to have
template<typename T>
StackOfNodees<T>::StackOfNodees()
{
m_top=nullptr;
m_size=0;
}
Rather than
StackOfNodees::StackOfNodees()
{
m_top=nullptr;
m_size=0;
}
Change all definitions and move them into StackOfNodees.h file from .hpp. You do not need an extra .hpp file.
Example:
// File a.h
template<typename T>
class A
{
public:
A();
// the rest of the class ....
};
template<typename T>
A<T>::A()
{
// ...
}
file app.cpp
#include "a.h"
void main()
{
A<int> a;
...
}
An extra .hpp file makes code less readable as it breaks reading flow. If you are still required to split your code in that manner then you need to include .hpp into .h file with #include "StackOfNodes.hpp" instruction in the bottom of .h file (a rather unconventional approach).
When you are writing a template class, you must provide definition of the template class in the same file where the declaration itself lies, so that the compiler can instantiate the actual class when compiling.
In this specific case, put the definitions in StackOfNodees.hpp back to the template class declaration in the file StackOfNodees.h after changing this int specific one to general type T one. This is a simple tutorial about the format of a template class.
Related
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed last year.
I have a problem. I have implemented a Queue, while using a Class "Queue" and a Class "Element".
the problem i have now is, that I can't work out how to create the template for class Element.
If I don't use the template and just use int instead of T. Everything works fine. I already looked for many examples on the Internet. But nobody uses two classes, which is probably more efficient. I think my problem is that i don't know how to use the pointer in templates.
PS: The template in Queue.h and.cpp works i think, but if i start trying to create a template for Element it doesn't work.
My Queue.h file
#ifndef ELEMENT_H
#define ELEMENT_H
#include "Element.h"
template <class T>
class Queue{
public:
explicit Queue(int max_queue);
~Queue() = default;
void enqueue(T inhalt);
Element* dequeue();
Element* show();
bool isEmpty();
private:
Element<T>* front{};
Element<T>* back{};
int max;
int anzahl = 0;
};
#endif
My Queue.cpp file
#include "Queue.h"
#include <iostream>
#include <string>
template <class T>
Queue<T>::Queue(int max_queue){
max = max_queue;
}
template <class T>
void Queue<T>::enqueue(T inhalt){
Element* e = new Element(inhalt);
if(max > anzahl){
if(isEmpty()){
front = back = e;
}else{
back->setNext(e);
back = e;
}
} anzahl++;
}
template <class T>
Element* Queue<T>::dequeue(){
Element* e = front;
front = front->getNext();
e->setNext(nullptr);
return e;
}
template <class T>
bool Queue<T>::isEmpty()
{
return anzahl == 0;
}
template <class T>
Element* Queue<T>::show()
{
return front;
}
My Element.h file
#ifndef QUEUE_H
#define QUEUE_H
class Element{
public:
explicit Element(int);
~Element() = default;
int getInhalt()const;
void setInhalt(int);
Element*getNext()const;
void setNext(Element*);
protected:
int inhalt;
Element* next;
};
#endif
My Element.cpp file
#include <string>
#include "Element.h"
Element::Element( int inhalt_element )
{
inhalt = inhalt_element;
next = nullptr;
}
int Element::getInhalt() const {
return inhalt;
}
void Element::setInhalt(int inhalt) {
Element::inhalt = inhalt;
}
Element* Element::getNext() const {
return next;
}
void Element::setNext(Element *next) {
Element::next = next;
}
The warning I'm getting is main.cpp:(.text+0x1a): undefined reference to `Queue::Queue(int)'
And If I try to use a template for the element class. There are hundreds of lines in the warnings, so I know I'm thinking completely wrong.
I am still pretty novice if it is about programming so any help or any idea would be really appreciated.
Thank you
The implementation of template classes must be done in the .h
The following code compiles.
#include <iostream>
#include <string>
template <class T>
class Element{
public:
Element( T inhalt_element ){
inhalt = inhalt_element;
next = nullptr;
}
T getInhalt() const {
return inhalt;
}
void setInhalt(T inhalt) {
this->inhalt = inhalt;
}
Element<T>* getNext() const {
return next;
}
void setNext(Element<T> *next) {
this->next = next;
}
protected:
T inhalt;
Element<T>* next;
};
template <class T>
class Queue{
public:
Queue(int max_queue){
max = max_queue;
}
void enqueue(T inhalt){
Element<T>* e = new Element<T>(inhalt);
if(max > anzahl){
if(isEmpty()){
front = back = e;
}else{
back->setNext(e);
back = e;
}
} anzahl++;
}
Element<T>* dequeue(){
Element<T>* e = front;
front = front->getNext();
e->setNext(nullptr);
return e;
}
bool isEmpty(){
return anzahl == 0;
}
Element<T>* show(){
return front;
}
private:
Element<T>* front{};
Element<T>* back{};
int max;
int anzahl = 0;
};
int main() {
std::cout << "Hello World!";
Queue<int> queue(10);
return 0;
}
I was working on this code, when I came across this redefinition error when I called it in my enqueue function. I've looked everywhere on how to fix it, but to no avail. I've used the header guard and I don't think I've redefined it anywhere else, I'm honestly pretty stuck here. Help is greatly appreciated. This is a little bit different from the cases I've looked up already, since they're not using templates.
#pragma once
#include <cstdio> // Needed for NULL
using namespace std;
template <class T>
class Node { // this is where the error happens, says "redefinition of class Node<T>" here, adds in a note that there's a previous definition of class Node<T> here.
public:
Node<T>* next;
T data;
Node();
Node(T dat);
}; // Node
template <class T>
Node<T>::Node(){
next = NULL;
}
template <class T>
Node<T>::Node(T thedata){
next = NULL;
data = thedata
}
//PriorityQueue.h
//There is a #pragma once at the top of the file.
template <class T>
void PriorityQueue<T>::enqueue(const T& x){
Node<T>* tempN;
Node<T>* newN = new Node<T>(x);
if(head == NULL || newN < head){
head = newN;
head->next = NULL;
}
else{
tempN = head;
while(tempN->next != NULL && tempN < newN){
tempN = tempN->next;
}
newN->next = tempN->next;
tempN->next = newN;
}
}
template <class T>
T& PriorityQueue<T>::peek() const throw(EmptyDataCollectionException){
return head->data;
}
#include "Queue.h"
#include "Event.h"
#include "PriorityQueue.h"
#include "EmptyDataCollectionException.h"
#include <iostream>
using namespace std;
int main () {
Event x;
Event x1;
Event x2;
//type 0 is arrival, type 1 is departure.
x.setLength(10);
x.setArrivaltime(5);
x1.setLength(4);
x1.setArrivaltime(3);
x2.setLength(4);
x2.setArrivaltime(8);
PriorityQueue<Event> Q;
Q.enqueue(x);
Q.enqueue(x1);
Q.enqueue(x2);
Event y = Q.peek();
cout << endl << "top: " << y;
return 0;
} // main
#pragma once
using namespace std;
typedef enum etype { arrival, departure } EventType;
// Desc: Represents a simulation event
class Event {
private:
EventType type;
unsigned arrivaltime;
// standing for arrival time.
unsigned length;
public:
//the default constructor for event.
Event();
EventType getType() const;
unsigned getArrivaltime() const;
unsigned getLength() const;
void setType(const EventType atype);
void setArrivaltime(const unsigned AnArrivaltime);
void setLength(const unsigned ALength);
// Desc: Comparators
bool operator<(const Event &r);
bool operator>(const Event &r);
bool operator<=(const Event &r);
bool operator>=(const Event &r);
friend ostream & operator<<(ostream & os, const Event & r);
}; // Event
#pragma once
#include "EmptyDataCollectionException.h"
#include <cstdio>
using namespace std;
template <class T>
class Queue {
private:
static unsigned const INITIAL_SIZE = 6;
int * arr;
unsigned size;
unsigned capacity;
unsigned frontindex;
unsigned backindex;
/* you choose your implementation */
Edit: Queue.h, Node.h, PriorityQueue.h and Event.h all have #pragma once.
Okay, EVERYTHING is in there now, I just felt like it would get really cluttered.
We have an assignment to create a Binary Search Tree with some basic functions. I feel I'd be capable of scraping by if it weren't for the files included with the assignment that we need to adhere to in order for the graders to implement our code with their grading program. Students are given a file called "Factory.cpp" which has a function that attempts to return an object of "BinarySearchTree" (return new BinarySearchTree();). However, VS 2013 gives me the error seen in the title. After some research, I can't find any infomration I can implement into my own problem to get rid of the error. Template classes are obviously more abstract and I can't find out what to include/leave out, etc to make things work.
The following is my incomplete code I have so far in my BinarySearchTree.h:
#pragma once
#include "BSTInterface.h"
#include "NodeInterface.h"
#ifndef BINARY_SEARCH_TREE_H
#define BINARY_SEARCH_TREE_H
struct BTNode :public NodeInterface{
// Data Fields
int data;
BTNode* left;
BTNode* right;
// Constructor
BTNode(const int& the_data,
BTNode* left_val = NULL,
BTNode* right_val = NULL) :
data(the_data), left(left_val), right(right_val) {}
// Destructor (to avoid warning message)
virtual ~BTNode() {}
// Interface Functions
int getData(){
return data;
}
NodeInterface* getLeftChild(){
return left;
}
NodeInterface* getRightChild(){
return right;
}
}; // End BTNode
#include <sstream>
template<class T>
class BinarySearchTree:public BSTInterface
{
public:
BTNode* root;
// BST Constructor / Deconstructor
BinarySearchTree() : root(NULL){}
//BinarySearchTree(const int& the_data,
// const BinarySearchTree& left_child = BinarySearchTree(),
// const BinarySearchTree& right_child = BinarySearchTree()) :
// root(new BTNode(the_data, left_child.root, right_child.root)){}
virtual ~BinarySearchTree(){}
// Interface Functions ----------------------
NodeInterface* getRootNode(){
return root;
}
bool add(int data){
return addRec(root, data);
}
bool addRec(BTNode* &x, int data){
if (x == NULL){
if (Search(root, data) == true){
return false;
}
else{
root = GetNewNode(data);
return true;
}
}
if (data == x->data){
return false;
}
if (x != NULL){
if (data < x->data){
return addRec(x->left, data);
}
if (data > x->data){
return addRec(x->right, data);
}
}
}
bool remove(int data){
return false;
}
bool removeRec(BTNode* &x, int data){
return false;
}
void clear(){
}
// ------------------------------------------
// My Functions -----------------------------
BTNode* GetNewNode(int data){
BTNode* newNode = new BTNode();
newNode->data = data;
newNode->left = newNode->right = NULL;
return newNode;
}
bool Search(BTNode* root, int data) {
if (root == NULL) {
return false;
}
else if (root->data == data) {
return true;
}
else if (data < root->data) { // had <= instead
return Search(root->left, data);
}
else if (data > root->data) { // had no "if"
return Search(root->right, data);
}
}
// ------------------------------------------
};
#endif
Which is derived from the following 2 "Interface" files:
NodeInterface.h:
//YOU MAY NOT MODIFY THIS DOCUMENT
#pragma once
#include <iostream>
class NodeInterface {
public:
NodeInterface() {}
virtual ~NodeInterface() {}
/*Returns the data that is stored in this node*/
virtual int getData() = 0;
/*Returns the left child of this node or null if it doesn't have one.*/
virtual NodeInterface * getLeftChild() = 0;
/*Returns the right child of this node or null if it doesn't have one.*/
virtual NodeInterface * getRightChild() = 0;
};
BSTInterface.h
//YOU MAY NOT MODIFY THIS DOCUMENT
#pragma once
#include "NodeInterface.h"
using namespace std;
class BSTInterface {
public:
BSTInterface() {}
virtual ~BSTInterface() {}
//Please note that the class that implements this interface must be made
//of objects which implement the NodeInterface
/*Returns the root node for this tree*/
virtual NodeInterface * getRootNode() = 0;
/*Attempts to add the given int to the BST tree*/
virtual bool add(int data) = 0;
/*Attempts to remove the given int from the BST tree*/
virtual bool remove(int data) = 0;
/*Removes all nodes from the tree, resulting in an empty tree.*/
virtual void clear() = 0;
};
Then they give us "Factory.h" and "Factory.cpp," which I believe they use to grab our BinarySearchTree from in order to grade using their grading program:
Factory.h:
#include "BSTInterface.h"
using namespace std;
/*
WARNING: It is expressly forbidden to modify any part of this document, including its name
*/
class Factory
{
public:
static BSTInterface * getBST();
};
Factory.cpp:
#include "Factory.h"
#include "BinarySearchTree.h"
//You may add #include statements here
/*
You will MODIFY THIS DOCUMENT.
getBST()
Creates and returns an object whose class extends BSTInterface.
This should be an object of a class you have created.
Example: If you made a class called "BinarySearchTree", you might say, "return new BinarySearchTree();".
*/
BSTInterface * Factory::getBST()
{
return new BinarySearchTree();//Modify this line
}
In "Factory.cpp", BinarySearchTree is marked as an error in VS with the message "argument list for class template is missing." How do I fix this? Along with any other errors you see.
Also, how would I declare a new BinarySearchTree object in a main() and call its functions in order to test it?
For that error, in these lines:
template<class T>
class BinarySearchTree:public BSTInterface
{
just get rid of the first line. That line is telling the compiler that you BinarySearchTree class is a template class. But since your class uses an int for data it would seem that is not needed.
I haven't looked at your other code so I won't comment on anything else.
Errors:
delimiters.cpp(41): error C2784: 'std::_String_iterator<_Elem,_Traits,_Alloc>
std::operator + (_String_iterator<_Elem,_Traits,_Alloc>::difference_type,std::_String_iterator<_Elem,_Traits,_Alloc>)' : could not deduce template argument for 'std::_String_iterator<_Elem,_Traits,_Alloc>' from 'char'
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\xstring(434) : see declaration of 'std::operator +'
stacklinked.cpp(20): error C2061: syntax error : identifier 'StackNode'
stacklinked.cpp(28): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
stacklinked.cpp(28): error C2063: 'StackNode' : not a function
stacklinked.cpp(28): fatal error C1903: unable to recover from previous error(s); stopping compilation
Responsive Code:
#ifndef STACKLINKED_CPP
#define STACKLINKED_CPP
#include <iostream>
#include "StackLinked.h"
//--------------------------------------------------------------------
template <typename DataType>
StackLinked<DataType>::StackNode(const DataType& newDataItem,
StackLinked<DataType>::StackNode* nextPtr)
//::StackNode
// Creates a stack node containing item newDataItem and next pointer
// nextPtr.
: dataItem(newDataItem), next(nextPtr)
{
}
//--------------------------------------------------------------------
template <typename DataType>
StackLinked<DataType>::StackLinked(int maxNumber)
: top(0)
// Creates an empty stack. The parameter maxNumber is provided for
// compatability with the array implementation and is ignored.
{
}
//--------------------------------------------------------------------
template <typename DataType>
StackLinked<DataType>::StackLinked(const StackLinked& other)
// Copy constructor for linked stack
: top( 0 )
{
(void) operator=(other); // Use operator=, ignore return value
/*
// Alternatively, could duplicate essentially all the code from
// operator= and insert below.
if( ! other.isEmpty() ) {
// Copy first node
top = new StackNode(other.top->dataItem, 0);
StackNode *otherTemp = other.top->next;
StackNode *thisTemp=0, *thisPrevious=top;
// Copy rest of nodes
while( otherTemp != 0 )
{
thisTemp = new StackNode(otherTemp->dataItem, 0);
thisPrevious->next = thisTemp;
thisPrevious = thisTemp;
otherTemp = otherTemp->next;
}
}
*/
}
//--------------------------------------------------------------------
template <typename DataType>
StackLinked<DataType>& StackLinked<DataType>::operator=(const StackLinked& other)
// Overloaded assignment operator for the StackLinked class.
// Because this function returns a StackLinked object reference,
// it allows chained assignment (e.g., stack1 = stack2 = stack3).
{
// Self-assignment protection
if( this != &other ) return *this;
clear(); // Clear existing nodes
if( ! other.isEmpty() )
{
// Copy first node
top = new StackNode(other.top->dataItem, 0);
StackNode *otherTemp = other.top->next;
StackNode *thisTemp=0, *thisPrevious=top;
// Copy rest of nodes
while( otherTemp != 0 )
{
thisTemp = new StackNode(otherTemp->dataItem, 0);
thisPrevious->next = thisTemp;
thisPrevious = thisTemp;
otherTemp = otherTemp->next;
}
}
return *this;
}
//--------------------------------------------------------------------
template <typename DataType>
StackLinked<DataType>::~StackLinked()
// Destructor. Frees the memory used by a stack.
{
clear();
}
//--------------------------------------------------------------------
template <typename DataType>
void StackLinked<DataType>::push(const DataType& newDataItem) throw (logic_error)
// Inserts newDataItem onto the top of a stack.
{
if (isFull()) {
// Not likely with linked implementation
throw logic_error("push() while stack full");
}
top = new StackNode(newDataItem, top);
}
//--------------------------------------------------------------------
template <typename DataType>
DataType StackLinked<DataType>::pop() throw (logic_error)
// Removes the topmost item from a stack and returns it.
{
if (isEmpty()) {
throw logic_error("pop() while stack empty");
}
StackNode* temp = top;
top = top->next;
DataType value = temp->dataItem;
delete temp;
return value;
}
//--------------------------------------------------------------------
template <typename DataType>
void StackLinked<DataType>::clear()
// Removes all the data items from a stack.
{
for (StackNode* temp = top; top != 0; temp = top)
{
top = top->next;
delete temp;
}
// Invariant: At this point in the code, top == 0.
// Top does not heed to explicitly set to 0. It was
// either 0 before the loop, or emerged from the loop as 0.
}
//--------------------------------------------------------------------
template <typename DataType>
bool StackLinked<DataType>::isEmpty() const
// Returns true if a stack is empty. Otherwise, returns false.
{
return top == 0;
}
//--------------------------------------------------------------------
template <typename DataType>
bool StackLinked<DataType>::isFull() const
// Returns true if a stack is full. Otherwise, returns false.
{
return false;
/*
// Alternatively, can use implementation below.
// This is a somewhat awkward way to test if the list is full.
// If a node can be successfully allocated than the list is not
// full. If the allocation fails it is implied that there is no
// more free memory therefore the list is full.
// We are not aware of any other standard/portable way of
// performing the test. And this can fail due to external issues
// such as the system exhausting swap or another thread stealing
// the remaining memory between when isFull returns its result and
// the caller does something that assumes that isFull() returned
// a valid answer.
//
// Alternatives include just the line "return false", which is
// probably good enough in this context, or platform-dependent
// checks for available memory.
StackNode* temp;
DataType junk;
try
{
temp = new StackNode( junk, 0 );
}
catch ( bad_alloc &e )
{
return true;
}
delete temp;
return false;
*/
}
//--------------------------------------------------------------------
template <typename DataType>
void StackLinked<DataType>::showStructure() const
// Linked list implementation. Outputs the data elements in a stack.
// If the stack is empty, outputs "Empty stack". This operation is
// intended for testing and debugging purposes only.
{
if( isEmpty() )
{
cout << "Empty stack" << endl;
}
else
{
cout << "Top\t";
for (StackNode* temp = top; temp != 0; temp = temp->next) {
if( temp == top )
{
cout << '[' << temp->dataItem << "]\t";
}
else
{
cout << temp->dataItem << "\t";
}
}
cout << "Bottom" << endl;
}
}
#endif //#ifndef STACKLINKED_CPP
Here's the header file, StackLinked.h
//--------------------------------------------------------------------
//
// Laboratory 6 StackArray.h
//
// Class declaration for the array implementation of the Stack ADT
//
//--------------------------------------------------------------------
#ifndef STACKARRAY_H
#define STACKARRAY_H
#include <stdexcept>
#include <iostream>
using namespace std;
#include "Stack.h"
template <typename DataType>
class StackLinked : public Stack<DataType> {
public:
StackLinked(int maxNumber = Stack<DataType>::MAX_STACK_SIZE);
StackLinked(const StackLinked& other);
StackLinked& operator=(const StackLinked& other);
~StackLinked();
void push(const DataType& newDataItem) throw (logic_error);
DataType pop() throw (logic_error);
void clear();
bool isEmpty() const;
bool isFull() const;
void showStructure() const;
private:
class StackNode {
public:
StackNode(const DataType& nodeData, StackNode* nextPtr);
DataType dataItem;
StackNode* next;
};
StackNode* top;
};
#endif //#ifndef STACKARRAY_H
Here's another header file, Stack.h
//--------------------------------------------------------------------
//
// Laboratory 6 Stack.h
//
// Class declaration of the abstract class interface to be used as
// the basis for implementations of the Stack ADT.
//
//--------------------------------------------------------------------
#ifndef STACK_H
#define STACK_H
#include <stdexcept>
#include <iostream>
using namespace std;
template <typename DataType>
class Stack {
public:
static const int MAX_STACK_SIZE = 8;
virtual ~Stack();
virtual void push(const DataType& newDataItem) throw (logic_error) = 0;
virtual DataType pop() throw (logic_error) = 0;
virtual void clear() = 0;
virtual bool isEmpty() const = 0;
virtual bool isFull() const = 0;
virtual void showStructure() const = 0;
};
template <typename DataType>
Stack<DataType>::~Stack()
// Not worth having a separate class implementation file for the destuctor
{}
#endif // #ifndef STACK_H
So, I've included all corresponding headers since this program utilizes inheritance. Please continue to help me debug this program. All help is well-appreciated.
You probably want to replace
StackLinked<DataType>::StackNode(...)
by
StackLinked<DataType>::StackNode::StackNode(...)
that is the constructor of class StackNode called as usual StackNode::StackNode inside the class StackLinked<DataType>.
I created a new project in Xcode 5.0 to implement a Queue class as following:
I created a .h file called QueueArray.h and it contains the following:
#ifndef __Queue__QueueArray__
#define __Queue__QueueArray__
#include <iostream>
template <class T>
class QueueArray
{
public:
QueueArray(int cap);
~QueueArray();
void Enqueue(T& val);
T Dequeue(void);
T GetFirst(void);
T GetLast(void);
bool IsEmpty(void);
bool IsFull(void);
void Clear(void);
private:
T* data;
int capacity, size, first, last;
};
#endif
and a .cpp file called QueueArray.cpp that contains the following:
#include "QueueArray.h"
using namespace std;
template <class T>
QueueArray<T>::QueueArray(int cap)
{
capacity = cap;
data = new T[capacity];
size = 0;
first = last = -1;
}
template <class T>
QueueArray<T>::~QueueArray(void)
{
delete [] data;
}
template <class T>
void QueueArray<T>::Enqueue(T& el)
{
if(IsFull() == true)
{
printf("\n Can't enqueue into a full queue!");
return;
}
if(IsEmpty() == true)
first = last = 0;
else if(last == capacity-1)//if at the last entry
last = 0; //wrap around to the first entry
else
last++;
data[last] = el;
size++;
}
template <class T>
T QueueArray<T>::Dequeue()
{
if(IsEmpty() == true)
{
printf("\n Can't dequeue from an empty queue!");
return -1;
}
T el = data[first];
if(first == last) //if only one element in queue
last = first = -1; //we'll get an empty queue
else if(first == capacity-1) //if at the last entry
first = 0; //wrap around to the first entry
else //normal case
first++;
size--;
return el;
}
template <class T>
T QueueArray<T>::GetFirst()
{
return data[first];
}
template <class T>
T QueueArray<T>::GetLast()
{
return data[last];
}
template <class T>
bool QueueArray<T>::IsEmpty(void)
{
return size == 0;
}
template <class T>
bool QueueArray<T>::IsFull(void)
{
return size == capacity;
}
and a main.cpp file that contains the following:
#include <iostream>
#include "QueueArray.h"
using namespace std;
int main(int argc, const char * argv[])
{
QueueArray<int> q(100);
for (int i=0; i<100; i++)
{
q.Enqueue(i);
}
for (int i=0; i<100; i++) {
cout<<q.Dequeue()<<endl;
}
return 0;
}
When I try to run the project, a message appears saying "Build Failed" and here is a screenshot of the errors:
How to fix that?
The compiler needs to see the definition of the Template before using it.
http://www.parashift.com/c++-faq-lite/templates-defn-vs-decl.html
There are more than one solution:
a. Move the definitions from .cpp file to the .h file
b. Use the export keyword if your compiler supports
http://www.parashift.com/c++-faq-lite/separate-template-fn-defn-from-decl-export-keyword.html
c. Add an inline declaration:
http://www.parashift.com/c++-faq-lite/separate-template-fn-defn-from-decl.html
You need to include the template definitions in-line with their declarations. An easy solution to this is to rename QueueArray.cpp to something like QueueArray_impl.h and #include it from the bottom of QueueArray.h
#ifndef __Queue__QueueArray__
#define __Queue__QueueArray__
#include <iostream>
template <class T>
class QueueArray
{
public:
QueueArray(int cap);
~QueueArray();
void Enqueue(T& val);
T Dequeue(void);
T GetFirst(void);
T GetLast(void);
bool IsEmpty(void);
bool IsFull(void);
void Clear(void);
private:
T* data;
int capacity, size, first, last;
};
#include "QueueArray_impl.h"
#endif