How do I create a template object based off of user input? - c++

I have made an array based queue with a template so that the user can decide what kind of data is held inside the queue but I cannot figure out how gather input and then from that create a queue of that data type.
Here is my Queue
#include <memory>
using namespace std;
template<class itemType>
class Queue
{
private:
unique_ptr<itemType []> queueArray;
int queueSize;
int front;
int rear;
int numItems;
public:
Queue(int);
itemType peekFront();
void enqueue(itemType item);
void dequeue();
bool isEmpty() const;
bool isFull() const;
void clear();
};
And I have tried this and many other ways but cant figure out how to tell what type of data the user inputs and then create a Queue with that type of data.
int main()
{
const int MAXSIZE = 5;
int choice;
cout << "1. integer queue\n" << "2. string queue\n" << "3. float queue\n";
choice = menu();
if(choice == 1)
{
Queue<int> newQueue(MAXSIZE);
int data;
}
else if(choice == 2)
{
Queue<string> newQueue(MAXSIZE);
string data;
}
else if(choice == 3)
{
Queue<float> newQueue(MAXSIZE);
float data;
}
else
cout << "Number needs to be 1-3." << endl;
cout << "Enter an item to add" << endl;
cin >> data;
newQueue->enqueue(data);
Thanks everyone for the help! I almost have it done, but now that I have all virtual functions how do I call peekFront()? Since the virtual functions can't return itemType right?

You need runtime polymorphism to solve this problem. This can either be achieved with a base class:
class IQueue {
virtual ~IQueue() = default;
virtual void enqueue(istream&) = 0;
};
template<class itemType>
class Queue : public IQueue
{
//...
public:
void enqueue(istream& is) override {
itemType item;
is >> item;
enqueue(item);
}
//...
};
And use as a pointer
int main() {
//...
unique_ptr<IQueue> newQueue;
//...
if(choice == 1)
{
newQueue.reset(new Queue<int>(MAXSIZE));
int data;
}
//...
newQueue->enqueue(cin);
//...
}
Or something like std::variant.

Well, you are almost there.
You just need to not loose the scope of your data and newQueue variables.
template <typename T>
T input()
{
T data;
cout << "Enter an item to add" << endl;
cin >> data;
return data;
}
int main()
{
const int MAXSIZE = 5;
int choice;
cout << "1. integer queue\n" << "2. string queue\n" << "3. float queue\n";
choice = menu();
if(choice == 1)
{
Queue<int> newQueue(MAXSIZE);
newQueue->enqueue(input<int>());
}
else if(choice == 2)
{
Queue<string> newQueue(MAXSIZE);
newQueue->enqueue(input<string>());
}
else if(choice == 3)
{
Queue<float> newQueue(MAXSIZE);
newQueue->enqueue(input<float>());
}
else
cout << "Number needs to be 1-3." << endl;
}
You still have some problem with this architecture, for example, maybe you want to move your queues outside these ifs, otherwise you can't use them anymore. (Read about scope).
You could also look at std::variant for these kind of situations.

Related

Error in converting class to template class

Code is a little long because I can't really trace the source of the error, so I'm not sure how much more I can remove (still new to C++ templates)
Already omitted are member functions and methods that I've also converted to templates, I don't think they're relevant for the error.
Below was a given class that I've been converting to an abstract template class, when compiled, I get the following compile-time error:
1.cpp:116:3: error: no matching function for call to 'testPFArrayD'
testPFArrayD();
1.cpp:87:6: note: candidate template ignored: couldn't infer template
argument 'T' void testPFArrayD()
Line 166 is the Main() call for the function testPFArrayD(). The actual purpose of the class isn't very important in this case, I just need to know the issue in converting it to a template.
The full-length, original source code (not converted to a template) for the class is here
#include <iostream>
using namespace std;
template <typename T>
class PFArrayD
{
public:
PFArrayD();
PFArrayD(int capacityValue);
PFArrayD(const PFArrayD& pfaObject);
void addElement(T element);
bool full() const { return (capacity == used); }
int getCapacity() const { return capacity; }
int getNumberUsed() const { return used; }
void emptyArray() { used = 0; }
double& operator[](T index);
PFArrayD& operator =(const PFArrayD& rightSide);
~PFArrayD();
private:
double *a;
int capacity;
int used;
};
template <typename T>
PFArrayD<T>::PFArrayD() :capacity(50), used(0)
{
a = new T[capacity];
}
template <typename T>
void testPFArrayD()
{
int cap;
cout << "Enter capacity of this super array: ";
cin >> cap;
PFArrayD() temp (cap); //?????????????????
cout << "Enter up to " << cap << " nonnegative numbers. \n";
cout << "Place a negative number at the end. \n";
double next;
cin >> next;
while ((next >= 0) && (!temp.full()))
{
temp.addElement(next);
cin >> next;
}
cout << "You entered the following " << temp.getNumberUsed() << " numbers:\n";
int index;
int count = temp.getNumberUsed();
for (index = 0; index < count; index++)
cout << temp[index] << " ";
cout << endl;
cout << "(plus a sentinel value.)\n";
}
int main()
{
cout << "This program tests the class PFArrayD.\n";
char ans;
do {
testPFArrayD();
cout << "Test again? (y/n) ";
cin >> ans;
} while ((ans == 'y') || (ans == 'Y'));
//system("pause");
return 0;
}

C++ Out Of Range When using Vector

So I have created a Binary Search Tree (BST) by placing nodes into a vector. These nodes store 3 values, a user input int ID, a user input int age, and a user string input name.
When inserting these nodes into the vector, they are stored going in ascending order.
Currently I'm working with two nodes.
104 10 Bob
102 11 Steve
When pushing back the first node, there are no problems; however, when attempting to push back the second node, I am getting an out_of_bounds error thrown by the vector class.
I believe something is wrong with my insert function when attempting to switch the positions of these two nodes, however I can't tell exactly where the issue lies.
#include "BinaryTree.h"
#include <string>
#include <iostream>
#include <vector>
using namespace std;
int index;
struct Node
{
int ID;
int age;
string name;
Node()
{
}
Node(int id, int Age, string nm)
{
this->ID = id;
this->age = Age;
this->name = nm;
}
};
vector<Node> binaryTree;
BST::BST()
{
}
void BST::start()
{
int choice;
cout << "What would you like to do?" << endl;
cout << "1. Add a node to the tree" << endl;
cout << "2. Delete a node from the tree" << endl;
cout << "3. Find a node in the tree" << endl;
cout << "4. Report the contents of the tree" << endl;
cout << "5. Exit program" << endl;
cin >> choice;
if (choice == 1)
{
insert();
}
if (choice == 3)
{
find();
}
if (choice == 4)
{
report();
}
}
void BST::insert()
{
int ID;
int AGE;
string NAME;
cout << "Please enter the ID number, age and name" << endl;
cin >> ID >> AGE >> NAME;
Node *tree = new Node(ID, AGE, NAME);
if (index == 0)
{
binaryTree.push_back(*tree);
index++;
}
if (index > 0)
{
if ((binaryTree.at(index - 1).ID) < ID)
{
binaryTree.push_back(*tree);
index++;
}
}
if (index > 0)
{
if ((binaryTree.at(index - 1).ID) > ID)
{
Node *temp = new Node();
*temp = binaryTree.at(index - 1);
binaryTree.at(index - 1) = *tree;
binaryTree.at(index) = *temp;
index++;
}
}
cout << "Added! Size: " << binaryTree.size() << endl;
cout << " " << endl;
start();
Would appreciate the help! Thanks!
Your vector doesn't resizes when you do this: binaryTree.at(index) = *tree;
Do push_back() then try sort
binaryTree.push_back(*tree;)
std::sort(binaryTree.begin(),binaryTree.end(),[](const Node& n1, const Node& n2){//do your comparations});
Or simply use std::set
If you want to work with std::vector without crashing, then your insert() have to look like this:
void BST::insert()
{
int ID;
int AGE;
string NAME;
cout << "Please enter the ID number, age and name" << endl;
cin >> ID >> AGE >> NAME;
//Node *tree = new Node(ID, AGE, NAME); // Don't use new here, there is no need in this
Node tree(ID, AGE, NAME);
binaryTree.push_back(tree);
std::sort(binaryTree.begin(), binaryTree.end(), [](const Node& n1, const Node& n2)
{
//compare your nodes here
return (n1.ID > n2.ID);
});
cout << "Added! Size: " << binaryTree.size() << endl;
cout << " " << endl;
start();
}
But this won't be a binary tree. You need other data structure to create binary tree, std::vector can't be binary tree.
There is a ready solution for you, look at std::set, It inserts elements like you need, you will need to add your custom compare function to std::set and everything will be fine.
Here is std::set example for you:
class Node
{
public:
Node(int id):ID(id){}
int ID;
};
class NodeComparator
{
public:
bool operator()(const Node& n1,const Node& n2)
{
return n1.ID < n2.ID;
}
};
int main()
{
std::set<Node, NodeComparator> set1;
set1.insert(10);
set1.insert(8);
set1.insert(14);
set1.insert(2);
return 0;
}
Here is what you need, std::set sorted ascending:
std::vector has methods other than push_back for inserting elements. Specifically, insert takes a position, where the new element is to be inserted. emplace is even better, as you don't even have to create an element to copy into the vector, you just pass the constructor arguments.
You can find the appropriate place to insert at with std::lower_bound.
#include <algorithm>
void BST::insert()
{
int ID;
int AGE;
std::string NAME;
std::cout << "Please enter the ID number, age and name" << std::endl;
std::cin >> ID >> AGE >> NAME;
auto pos = std::lower_bound(binaryTree.begin(), binaryTree.end(),
[](const Node& n1, const Node& n2) { return (n1.ID > n2.ID); });
binaryTree.emplace(pos, ID, AGE, NAME);
std::cout << "Added! Size: " << binaryTree.size() << endl;
std::cout << " " << std::endl;
// start(); // dubious, see below
}
As an aside, your insert method knowing about start is leaking assumptions that you may later want to change. It would be much better to contain that all within start, like:
void BST::start()
{
std::cout << "What would you like to do?" << std::endl;
std::cout << "1. Add a node to the tree" << std::endl;
std::cout << "2. Delete a node from the tree" << std::endl;
std::cout << "3. Find a node in the tree" << std::endl;
std::cout << "4. Report the contents of the tree" << std::endl;
std::cout << "5. Exit program" << std::endl;
for(int choice; (std::cin >> choice) && (choice != 5);)
{
switch (choice)
{
case 1: insert(); break;
case 3: find(); break;
case 4: report(); break;
}
}
}

Better way to code linked list?

I wrote this Linked List code and I am not able to create a single linked list since the value pointed by memory location of nodeValue in main function keep changing which in turn changes the head and tail value. I solved this by creating a Node object array((like nodeValue[5]) and passing the value, but this limits to 5 values. Is there a way to efficient way to code this without using a array of objects?
#include<iostream>
#include<string>
using namespace std;
class Node
{
public:
int value;
Node *nextNodePointer;
};
class linkedList
{
private:
int count = 0;
public:
Node *Head;
Node *Tail;
void AddNodeAfter(Node *);
//void removeNodeAfter(Node *);
void displayValues();
};
void linkedList::AddNodeAfter(Node *temp)
{
if (this->count == 0)
{
Head = temp;
Tail = temp;
count++;
}
else
{
Tail->nextNodePointer = temp;
Tail = temp;
count++;
}
}
Node createNodeObjects()
{
cout<< endl << "Enter integer value :";
Node temp;
cin >> temp.value;
temp.nextNodePointer = NULL;
return temp;
}
void linkedList::displayValues()
{
if (count == 0)
{
cout << endl << "Nothing to display";
}
else
{
Node value;
value = *Head;
for (int i = 1; i <= count; i++)
{
cout << endl << "Value: " << value.value;
value = *value.nextNodePointer;
}
}
}
int main()
{
cout << "Creating basic linked list" << endl;
linkedList LinkedList;
Node nodeValue;
while (1)
{
cout << endl << "Do you want to add a value to Node ?<Y/N> : ";
char choice;
cin >> choice;
if (choice == 'Y')
{
nodeValue = createNodeObjects();
LinkedList.AddNodeAfter(&nodeValue);
}
else
if (choice == 'N')
{
LinkedList.displayValues();
break;
}
else
cout << "Wrong choice" << endl;
}
}
In C++ , you can use list library ...
http://www.cplusplus.com/reference/list/list/

How do I access the properties of this object?

Okay, I've been battling this for awhile and I don't understand what I need to do. This is my LinkedList header.
// Non templated version
#pragma once
#ifndef __LINKEDLIST_H__
#define __LINKEDLIST_H__
// Get access to size_t definitions
#include <cstddef>
using std::size_t;
// A type alias for the stored type. Changing this changes what is stored
typedef int ItemType;
// Nodes for a linked list in C++
class Node
{
// A friend declaration allows LinkedList class to access the Node's private data
friend class LinkedList;
public:
Node(const ItemType& data, Node* next = nullptr);
private:
ItemType _data;
Node* _next;
};
// An linked list for C++
class LinkedList
{
public:
LinkedList();
LinkedList(const LinkedList&);
~LinkedList();
LinkedList& operator=(const LinkedList&);
ItemType pop_front();
ItemType& front();
void push_front(const ItemType& value);
void insert(size_t index, ItemType& data); // Replace these w/ iterators
void remove(size_t index);
size_t getSize() const;
private:
// Helper methods
void copy(const LinkedList &src);
void dealloc();
Node* find(size_t index) const;
// data
size_t _size;
Node *_head;
};
void LinkedList::insert(size_t index, Dweller &data){
Node* temp = this->_head;
while (temp->_next != NULL){
temp = temp->_next;
}
Node newNode = Node(data);
temp->_next = &newNode;
}
#endif
And this is my vault.h file:
#include <string>
#include <vector>
#include "linked_list.h"
using namespace std;
class Dweller{
public:
Dweller(const string& name, int& strength, int& agility, int& perception);
int getStrength();
int getAgility();
int getPerception();
string getName();
private:
string name;
int strength;
int agility;
int perception;
};
Dweller::Dweller(const string& name, int& strength, int& agility, int& perception){
if ((strength > 10) || (strength < 1)){
cout << "Invalid number." << endl;
}
if ((agility > 10) || (strength < 1)){
cout << "Invalid number." << endl;
}
if ((perception > 10) || (perception < 1)){
cout << "Invalid number." << endl;
}
this->name = name;
this->strength = strength;
this->agility = agility;
this->perception = perception;
}
int Dweller::getStrength(){
return this->strength;
}
int Dweller::getAgility(){
return this->agility;
}
int Dweller::getPerception(){
return this->perception;
}
string Dweller::getName(){
return this->name;
}
class Room{
public:
Room(const string& name, const string& statistic);
void print();
void add(Dweller&);
private:
string name;
string statistic;
LinkedList dwellers = LinkedList();
};
Room::Room(const string& name, const string& statistic){
this->name = name;
this->statistic = statistic;
}
void Room::add(Dweller& person){
dwellers.insert(0, person);
}
And the driver.cpp file that I can't edit. This is an assignment.
// driver.cpp
// Testing driver for Assignment 2
#include <iostream>
#include <locale>
#include <string>
#include "vault.h"
using std::cin;
using std::getline;
using std::cout;
using std::endl;
using std::string;
using std::locale;
using std::tolower;
int main()
{
std::locale loc;
// We create three rooms: Power Generator (Strength), Water Processing (Perception),
// and Diner (Agility)
Room power("Power Generator", "Strength");
Room water("Water Processing", "Perception");
Room diner("Diner", "Agility");
string prompt;
do
{
string charName;
cout << "What is the Dweller's name? ";
getline(cin, charName);
int str = 0, per = 0, agl = 0;
char room;
do
{
cout << "What is the character's Strength [1-10]? ";
cin >> str;
}
while(str <= 0 || str > 10);
do
{
cout << "What is the character's Perception [1-10]? ";
cin >> per;
}
while(per <= 0 || per > 10);
do
{
cout << "What is the character's Agility [1-10]? ";
cin >> agl;
}
while(agl <= 0 || agl > 10);
do
{
cout << "Which room [(P)ower, (W)ater, (D)iner]? ";
cin >> room;
room = tolower(room, loc);
}
while(room != 'p' && room != 'w' && room != 'd');
if(room == 'p')
power.add(Dweller(charName, str, per, agl));
else if(room == 'w')
water.add(Dweller(charName, str, per, agl));
else
diner.add(Dweller(charName, str, per, agl));
cout << "Are there more Dwellers [Y/N]? " << endl;
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // Flush newlines
getline(cin, prompt);
}
while(tolower(prompt[0], loc) == 'y');
power.print();
water.print();
diner.print();
}
The problem I'm having is that I keep getting that I cannot convert from const Dweller to const ItemType.
What I'm trying to do is add a Dweller object to a linkedlist.
Is there a reason for the LinkList class? If not why not do something like this instead? Vector has pretty much everything you need on that. Some other advice is don't use std::endl unless you need to do a flush. instead use \n.
// Get access to size_t definitions
#include <vector>
#include <iostream>
#include <locale>
#include <string>
class Dweller{
public:
Dweller(const std::string name, int strength, int agility, int perception);
int getStrength();
int getAgility();
int getPerception();
std::string getName();
private:
std::string name_;
int strength_;
int agility_;
int perception_;
};
Dweller::Dweller(const std::string name, int strength, int agility, int perception) :
name_{name},
strength_{strength},
agility_{agility},
perception_{perception}
{
if (strength > 10 || strength < 1) {
std::cout << "Invalid number.\n";
}
if ((agility > 10) || (strength < 1)){
std::cout << "Invalid number.\n";
}
if ((perception > 10) || (perception < 1)){
std::cout << "Invalid number.\n";
}
}
int Dweller::getStrength(){
return strength_;
}
int Dweller::getAgility(){
return agility_;
}
int Dweller::getPerception(){
return perception_;
}
std::string Dweller::getName(){
return name_;
}
class Room{
public:
Room(const std::string name, const std::string statistic);
void print();
void add(Dweller&);
private:
std::string name_;
std::string statistic_;
std::vector<Dweller> dwellers_;
};
Room::Room(const std::string name, const std::string statistic) :
name_{name},
statistic_{statistic}
{}
void Room::print()
{
for (auto& iter : dwellers_) {
std::cout << "\nName: " << iter.getName()
<< "\nStrength: " << iter.getStrength()
<< "\nAgility: " << iter.getAgility()
<< "\nPerception: " << iter.getPerception();
}
}
void Room::add(Dweller& person)
{
dwellers_.push_back(person);
}
int main()
{
std::locale loc;
// We create three rooms: Power Generator (Strength), Water Processing (Perception),
// and Diner (Agility)
Room power("Power Generator", "Strength");
Room water("Water Processing", "Perception");
Room diner("Diner", "Agility");
std::string prompt;
do
{
std::string charName;
std::cout << "What is the Dweller's name? ";
std::getline(std::cin, charName);
int str = 0, per = 0, agl = 0;
char room;
do
{
std::cout << "What is the character's Strength [1-10]? ";
std::cin >> str;
} while (str <= 0 || str > 10);
do
{
std::cout << "What is the character's Perception [1-10]? ";
std::cin >> per;
} while (per <= 0 || per > 10);
do
{
std::cout << "What is the character's Agility [1-10]? ";
std::cin >> agl;
} while (agl <= 0 || agl > 10);
do
{
std::cout << "Which room [(P)ower, (W)ater, (D)iner]? ";
std::cin >> room;
room = tolower(room, loc);
} while (room != 'p' && room != 'w' && room != 'd');
if (room == 'p')
power.add(Dweller(charName, str, per, agl));
else if (room == 'w')
water.add(Dweller(charName, str, per, agl));
else
diner.add(Dweller(charName, str, per, agl));
std::cout << "Are there more Dwellers [Y/N]? \n";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // Flush newlines
std::getline(std::cin, prompt);
} while (tolower(prompt[0], loc) == 'y');
power.print();
water.print();
diner.print();
std::cout << '\n';
system("PAUSE");
}
Start by making it possible to do what you want. Change the definition of Node to be templated
template <class ItemType>
class Node
{
//node, but with a few tweaks to replace the typedef of ItemType with the templating
}
Ditto with LinkedList
template <class ItemType>
class LinkedList
{
//lots of tweaks to replace node with templated node
...
Node<ItemType> *_head;
};
Then when you need to make the list:
LinkedList<Dweller> dwellers;

program skips over getline [duplicate]

This question already has answers here:
getline not asking for input? [duplicate]
(3 answers)
Closed 7 years ago.
When I run this program, and select option 1, it prints both cout statements in void CTree::Add() at once, jumping over the cin.getline(newPerson->name, 20);
I had the same piece of code in linked list program and it behaved properly, I am really stuck at how to fix this.
//header file
using namespace std;
struct PersonRec
{
char name[20];
int bribe;
PersonRec* leftLink;
PersonRec* rightLink;
};
class CTree
{
private:
PersonRec *tree;
bool IsEmpty();
void AddItem( PersonRec*&, PersonRec*);
void DisplayTree(PersonRec*);
public:
CTree();
//~CTree();
void Add();
void View();
};
//implementation file`
#include <iostream>
#include <string>
using namespace std;
#include "ctree.h"
CTree::CTree()
{
tree = NULL;
}
//PersonList::~MyTree()
//{
//
//}
bool CTree::IsEmpty()
{
if(tree == NULL)
{
return true;
}
else
{
return false;
}
}
void CTree::Add()
{
PersonRec* newPerson = new PersonRec();
cout << "Enter the person's name: ";
cin.getline(newPerson->name, 20);
cout << "Enter the person's contribution: ";
cin >> newPerson->bribe;
newPerson->leftLink = NULL;
newPerson->rightLink = NULL;
AddItem(tree, newPerson);
}
void CTree::View()
{
if (IsEmpty())
{
cout<<"The list is empy";
}
else
{
DisplayTree(tree);
}
};
void CTree::AddItem( PersonRec*& ptr, PersonRec* newPer )
{
if (tree == NULL)
{
ptr = newPer;
}
else if ( newPer->bribe < ptr->bribe)
AddItem(ptr->leftLink, newPer);
else
AddItem(ptr->rightLink, newPer);
}
void CTree::DisplayTree(PersonRec* ptr)
{
if (ptr == NULL)
return;
DisplayTree(ptr->rightLink);
cout<<ptr->name<<" "<<"$"<<ptr->bribe <<endl;
DisplayTree(ptr->leftLink);
}
//driver file
#include <iostream>
using namespace std;
#include <cstdlib>
#include "ctree.h"
int displayMenu (void);
void processChoice(int, CTree&);
int main (void)
{
int num;
CTree ct;
do
{
num = displayMenu();
if (num != 3)
processChoice(num, ct);
} while (num != 3);
return 0;
}
int displayMenu (void)
{
int choice;
cout << "\nMenu\n";
cout << "==============================\n\n";
cout << "1. Add student to waiting list\n";
cout << "2. View waiting list\n";
cout << "3. Exit program\n\n";
cout << "Please enter choice: ";
cin >> choice;
return choice;
}
void processChoice(int choice, CTree& myTree)
{
switch (choice)
{
case 1: myTree.Add (); break;
case 2: myTree.View (); break;
}
}
After you read choice in the displayMenu subroutine, you leave the remainder of the user's input line. Specifically, you leave the end-of-line indicator: '\n'. Later, when you read newperson->name, you are actually retrieving the remainder of the menu line, and not the name line.
You can use istream::ignore to consume the rest of menu choice line, before trying to read the name.
Replace the last two lines of displayMenu with these:
cin >> choice;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return choice;
Adding a
cin.ignore(2000, '\n');
before the input call fixes the problem!