Array of Generic Class Objects C++ - c++

I have a generic class Queue that contains a template Ttype2 as the placement holder for the type of data that will be stored in the information field of each node.
In my driver class I want to instantiate an array of Queue class objects but I can't seem to figure it out. How might I go about doing this?
These didn't work but illustrate what I'm trying to accomplish:
// Queue Complex[] = new Queue();//invalid use of template name without identifier list
//Queue<Ttype2> Complex[]; //template arg 1 is invalid
// vector<Queue> Complex2[];//invalid template arguments`
Queue Class declaration and constructor inside Queue.h header:
template <typename Ttype2>
class Queue
{
// Global Data Items
protected:
Node <Ttype2> Front, Rear;
int Length;
// member function prototypes
public:
Queue();
void AddRear(Node <Ttype2> ThisNode);
Node <Ttype2> RemoveFront();
void Modify(int Position, Node <Ttype2> ThisNode);
void ClearAll();
int GetSize();`
Node <Ttype2> GetNode(int Position);
Node <Ttype2>* toArray();
};`
// Constructor
template <typename Ttype2>
Queue <Ttype2> :: Queue()
{
Rear = Front = NULL;
Length = 0;
} // End of Constructor
`

This works:
Queue<int> *Complex = new Queue<int>();
Queue<int> Complex[1];
vector<Queue<int>> Complex2[1];
You need to give real params to your template when instantiating it.
Queue<Ttype2> // Ttype2 isn't a real type, use int, char, ...
Also you need to define your type Node<>. And if your want to assign NULL to Rear and Front it, first consider to make them pointers, second use nullptr instead of NULL.

I will add to Yola's solution that if I want to keep many different Queue<XXX> in a single array,
I usually create an interface class Queue_base.
class Queue_base{
public: virtual void func()=0;
};
template <typename Ttype2>class Queue : public Queue_base{
public: void func(){
//... some code
}
};
int main() {
Queue_base* complex[2];
complex[0]=new Queue<int>();
complex[1]=new Queue<float>();
complex[0]->func();
std::vector<Queue_base*> complex2;
complex2.push_back(new Queue<char>());
Queue<int>* c1=static_cast<Queue<int>*>(complex[0]);
return 0;
}
Here is live demo.
Note that using virtual function reduces performance a bit.
It will also lose the type (reduce to Queue_base*) and restrict some function calling, but it is useful for some real-world cases.
To extend its usage Node<T> can also inherit from a new class Node_Base that has all common function of Node<T>, e.g. :-
template <typename Ttype2> class Queue : public Queue_Base{
// Global Data Items
protected:
Node_Base* Front; //Front = new Node<Ttype2>();
Node_Base* Rear;
It depends on your demand though.

Related

Using or not using new for creation of a class in another

I have been solving a question, Dijkstra's Algorithm, in C++. I've implemented it using adjacency list.
So I have a class for a node, a class for a minHeap, and a class for the Graph.
class node
{
int vertex,weight;
node *next;
friend class Graph;
friend class minHeap;
public:
node();
node(int,int);
};
node::node(){
vertex=weight=0;
next=0;
}
node::node(int v,int wt){
vertex=v;
weight=wt;
next=0;
}
Do I define the minHeap class this way (without a friend function) and create an object in the getDijkSP() function normally, which allows me to use the object only in that function?
class minHeap
{
node *heap;
int heapSize,capacity,*pos;
public:
minHeap(int);
void addElement(node);
node extractMin();
void minHeapify(int);
void decreaseKey(int,int);
};
minHeap::minHeap(int cap){
heap=new node[capacity=cap];
heapSize=-1;
pos=new int[cap]();
} //eliminating other methods
class Graph
{
node **adjList;
int v;
bool *visited;
public:
Graph(int);
void addEdge(int,int,int);
void removeEdge(int,int);
bool existsEdge(int,int);
void getDijkSP();
};
Graph::Graph(int vertices){
adjList=new node*[v=vertices];
for(int i=0;i<v;i++)
adjList[i]=NULL;
}
void Graph::getDijkSP(){
minHeap hp(v); //here
hp.addElement(node(0,0));
for(int i=1;i<v;i++)
hp.addElement(node(i,INT_MAX));
while(!hp.isempty()){
node temp=hp.extractMin();
cout<<temp.vertex<<" "<<temp.weight<<endl;
for(node *current=adjList[temp.vertex];current;current=current->next)
hp.decreaseKey(current->vertex,current->weight+temp.weight);
}
}
(OR) Do I define the minHeap class with a friend function, so that I can create an object of the minHeap class using the new keyword? (And this helps me define the minHeap object in the scope of the Graph class, so that I can use it in all of its functions for other capabilities as well.)
class minHeap
{
node *heap;
int heapSize,capacity,*pos;
friend class Graph; //say like this
public:
minHeap(int);
void addElement(node);
node extractMin();
void minHeapify(int);
void decreaseKey(int,int);
};
minHeap::minHeap(int cap){
heap=new node[capacity=cap]();
heapSize=-1;
pos=new int[cap]();
}
class Graph
{
node **adjList;
int v;
bool *visited;
minHeap *hp; //and do this
public:
Graph(int);
void addEdge(int,int,int);
void removeEdge(int,int);
bool existsEdge(int,int);
void getDijkSP();
};
Graph::Graph(int vertices){
adjList=new node*[v=vertices];
for(int i=0;i<v;i++)
adjList[i]=NULL;
hp=new minHeap(v); //dynamic allocation
}
void Graph::getDijkSP(){
hp->addElement(node(0,0));
for(int i=1;i<v;i++)
hp->addElement(node(i,INT_MAX));
while(!hp->isempty()){
node temp=hp->extractMin();
cout<<temp.vertex<<" "<<temp.weight<<endl;
for(node *current=adjList[temp.vertex];current;current=current->next)
hp->decreaseKey(current->vertex,current->weight+temp.weight);
}
}
I have read this and a few other articles, but specifically want to know the advantages, disadvantages and the appropriateness of both the methods for such similar kinds of questions.
I've provided the constructors for the classes for better clarity.
Short answer would be NO. I would suggest you to read up on smart pointers and rewrite this whole mess. In C++ there is no real reason to use manual allocation in so simple project as this ever.
Also instead of assigning 0 or NULL to a pointer use nullptr, which is C++ symbol only for null pointers unlike the previous mentioned C values that are actually just a int 0 which may cause some unintentional errors.
Edit in response to your comment:
So I've decided to rewrite your code using actual modern C++ instead of this C code with simple classes. In your whole example there are almost no pointers or dynamic allocations needed. I wasn't absolutely sure who exactly should own the actual nodes so from the example I assumed that the MinHeap should. Also I didn't get the point of MinHeap::pos and Graph::visited from what I could see. I can explain any part of that code in more detail, just ask which.
Here is the code:
class Node {
// Only friend class required if you insist on keeping members of Node private.
// If they aren't meant to change, consider declaring them as public and const.
template <unsigned Size> friend class Graph;
public:
Node(int v, int wt) : vertex(v), weight(wt) {}
private:
// Default values written in here right after declarations
// There is no need for a default constructor. You never call it anyway.
int vertex;
int weight;
Node* next = nullptr;
};
// Template parameter because of internal use of std::array.
// If the capacity shouldn't be constant, use std::vector and remove template.
template <unsigned Capacity>
class MinHeap {
public:
// No constructor needed
// ---------------------
// One small tip: write parameter names in function declarations
// even if they aren't needed there for better readability of your code.
void addElement(Node n) { /* impl */ }
Node extractMin() { /* impl */ }
unsigned capacity() { return Capacity; }
bool isEmpty() { return heap.isEmpty(); }
private:
// Default values written in here right after declarations
int heapSize = -1;
std::array<Node, Capacity> heap;
};
// Template parameter because of internal use of std::array.
// If the vertex count shouldn't be constant, use std::vector and remove template.
template <unsigned Vertices>
class Graph {
public:
// No constructor needed
// ---------------------
void getDjikSP() {
hp.addElement({0, 0});
for (unsigned i = 1; i < hp.capacity(); ++i)
hp.addElement({0, INT_MAX});
while (!hp.isEmpty()) {
Node tmp = hp.extractMin();
std::cout << tmp.vertex << " " << tmp.weight << std::endl;
for (Node* current = adjList[tmp.vertex]; current != nullptr; current = current->next)
hp.decreaseKey(current->vertex, current->weight + tmp.weight);
}
}
private:
// Default values written in here right after declarations
std::array<Node*, Vertices> adjList;
MinHeap<Vertices> hp;
};
There is still a lot of space for improvements of this code, for example the MinHeaP::extractMin should maybe return Node&& if it is removed from the heap or const Node& if it should return a reference to the top, etc. To address all the problems and inefficiencies this can still have I would need to see the full code with all functions.

Issue with nested templated classes

I am trying to create a simple stack using templated classes. There seems to be an issue when one class calls the constructor of the other class.
#include <iostream>
#include <vector>
int g_MaxSize = 100;
template <class T>
class Stack;
template <class D>
class Node
{
private:
D data;
public:
Node(D value): data(value)
{
}
template <class T>
friend class Stack;
};
template <class T>
class Stack
{
private:
std::vector<Node<T>> stack;
int top;
public:
Stack(): stack(g_MaxSize), top(0)
{
}
void push(T val)
{
// make sure stack isnt full
stack[top++]= Node<T>(val);
}
Node<T> pop()
{
return stack[top--];
}
Node<T> peek()
{
return stack[top];
}
};
int main() {
Node<int> testNode(1) // *this works*
Stack<int> myStack;
myStack.push(3);
return 0;
}
The error is " No matching constructor for initialization of 'Node' ". As shown in the code above, Node constructor works on its own but it does not work when done through the Stack class.
The argument of vector needs a default constructor. Node is missing one, hence the error.
Your issue here is that stack(g_MaxSize) in Stack(): stack(g_MaxSize), top(0)
is requesting that you construct g_MaxSize default constructed Nodes in the vector. You can't do that though since Node is not default constructable.
You can add a default constructor to Node that will fix that. Another way would be to pass a default Node to the vector constructor like stack(g_MaxSize, Node<T>(1)). Lastly you could create the vector with zero size and then call reserve in the constructor body to allocate the storage for the Nodes without constructing them.

C++ Templated linked list getting data element of a complex data type

I've been working on updating my old templated linked list to be able to take a complex data type. But I have no idea how to make it be able to return the data element in the node class. Currently the code for my node class looks like this:
using namespace std;
#ifndef Node_A
#define Node_A
template <class T>
class Node
{
public:
Node();
~Node();
T getData();
Node* getNext();
void setData(T);
void setNext(Node*);
private:
Node *next;
T data;
};
template <class T>
Node<T>::Node()
{
next = NULL;
return;
}
template <class T>
Node<T>::~Node()
{
return;
}
template <class T>
T Node<T>::getData()
{
return data;
}
template <class T>
Node<T>* Node<T>::getNext()
{
return next;
}
template <class T>
void Node<T>::setData(T a)
{
data = a;
return;
}
template <class T>
void Node<T>::setNext(Node* a)
{
next = a;
return;
}
#endif
Now this works perfectly fine if the data type T is a primitive but if you use a non-primitive like say a struct it would give a runtime error. I presume because structs don't do operator overloading for = operator. Is there a simple way of fixing this without completely overhauling the class?
It's not about overloading the = operator, it's about implementing the assignment operator for the struct. If you do that, you won't need to change your Node class, unless I've missed something else.
The above assumes that you'll be making copies of the data inside the Node. Alternatively, you can pass the data by reference. In this case, you need to be careful that the data doesn't get deleted before the Node object is deleted, otherwise you'll get a crash when trying to access a deleted data object from your Node.

Reversing a generic doubly-linked list in C++

I'm trying to give my generic list class a reverse function. For some reason, my algorithm ain't workin' when I test it. I thought it made sense: swap the pointers to the first and last nodes of the list, then go through the list and for each node swap its pointers to the previous and next node.
Go easy on me, guys. I'm trying to get some practice with generic programming. Teach me the ways of a C++ purist.
Here's the swap function:
template <class T> void swap(T* a, T* b) {
T* tempPtr = a;
a = b;
b = tempPtr;
}
Here's the reverse function:
template <class T> void List<T>::reverse() {
if (size > 1) {
swap(firstNodePtr, lastNodePtr);
node* curNodePtr = firstNodePtr;
while (curNodePtr != NULL) {
swap(curNodePtr->prevNodePtr, curNodePtr->nextNodePtr);
curNodePtr = curNodePtr->nextNodePtr;
}
}
}
Here's the class, its members and prototypes for functions:
template <class T> class List {
public:
List();
~List();
void push_back(T);
void push_front(T);
T get_at(unsigned);
unsigned get_size();
void reverse();
private:
struct node {
T val;
node* prevNodePtr;
node* nextNodePtr;
};
node* firstNodePtr;
node* lastNodePtr;
unsigned size;
};
Your swap<T> function does not work: it exchanges pointers, which are copied by value into local variables of your function, which has no effect in the caller.
Dropping your own swap and replacing it with std::swap will fix this problem.
Since you pass the two pointers by value, the changes to a and b don't propagate out of the swap() function, making it a no-op.
One way to fix it is by passing the pointers by reference:
template <class T> void swap(T*& a, T*& b) {
Alternatively (and preferably) just use std::swap() instead of your own function.
If you exposed your node structure (or at least a bidirectional iterator type for your list), you could avoid the whole issue and just use std::reverse.
List<int> someList;
// fill with data
std::reverse(someList.begin(), someList.end()); // where begin returns a bidirectional iterator for the head, and end returns a bidirectional iterator for 1 element beyond the tail

C++ Invalid use of member function, did you forget the ( )?

I'm working on an assignment where I create my own container using templates. The container I am required to use is called Smaph, which takes in two pairs of numbers and does a variety of functions with them. I am only allowed to make a header file for this assignment. I've created a singly-linked class slink, that takes one template argument.
Currently, I am trying to get a feel for templates and learning how to use them, so I have a very simple example I was hoping you could help me with. I have a push_back function in my singly linked list class to add to my templates. For some reason, I can't add things to my slink because I get a compile time error that says, Invalid use of member function, (push_back), did you forget the ( )? Can someone explain to me why I am getting this error?
Thank you!
template <typename T>
class slink {
private:
struct node {
T datum;
struct node *next;
};
node *head, *tail;
public:
slink() : head(0), tail(0) {
}
~slink() {
clear();
}
void push_back(const T &datum) {
node *p = new node;
p->datum = datum;
p->next = 0;
if (!tail)
head = p;
else
tail->next = p;
tail = p;
}
template <typename Tfirst, typename Tsecond>
class Smaph {
public:
Smaph();
~Smaph();
Smaph(const Tfirst a, const Tsecond b) {
std::pair<Tfirst, Tsecond> pair1(a, b);
s.push_back(pair1);
}
private:
slink<std::pair<Tfirst, Tsecond> > s();
};
And finally, my main to test my program. All I want to do right now is add these two numbers to my singly linked list through my Smaph.
int main() {
Smaph<int, double> s(3, 6.3);
}
slink<std::pair<Tfirst, Tsecond> > s();
This is a declaration of a function called s that takes no arguments and returns a slink<std::pair<Tfirst, Tsecond> >. When the compiler sees you do s.push_back(pair1);, it wonders what you're trying to do to that poor function. Remove the () to make it a data member:
slink<std::pair<Tfirst, Tsecond> > s;
On this line you did:
slink<std::pair<Tfirst, Tsecond> > s();
This is declaring a function named s that returns slink<std::pair<Tfirst, Tsecond> >. But then you did this inside one of your member functions:
s.push_back(pair1);
That isn't right, which is why your compiler alerts you of invalid use of this member function.
To fix, remove the parameters:
slink<std::pair<Tfirst, Tsecond> > s;