How do you initialize template class members that uses other template classes? - c++

I'm having trouble correctly setting up and accessing my member functions of a class. This node class is being used to build a Max Heap Tree. However, when the tree is being initialized, I'm getting garbage data and not what I am initializing it to.
#ifndef HEAPNODE_H_INCLUDED
#define HEAPNODE_H_INCLUDED
#include <iostream>
#include <cstdlib>
#include <array>
using namespace std;
template <class Type> class HeapNode {
private:
int key;
Type value;
public:
HeapNode(int key, Type const &value) {
this->key = key;
this->value = value;
}
// Returns the key of the node
int getKey() {
return key;
}
// Returns the value of the node
Type getValue() {
return value;
}
// Displays the node
void displayNode() {
cout << "Key: " << key << "\tValue: " << value << endl;
}
};
#endif
Here is the class that builds my Heap Tree. I've tried setting the initializations in the constructor every which way, and I'm still getting junk data. In addition, I set the constructor to take an integer, but when I'm creating a tree in my driver program, it won't let me put an argument for it which initiates an array of that size.
#ifndef MAXHEAPTREE_H_tINCLUDED
#define MAXHEAPTREE_H_INCLUDED
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <string>
#include "HeapNode.h"
using namespace std;
template <class Type> class MaxHeapTree {
private:
HeapNode<Type> *array;
HeapNode<Type> *root;
int elementSize;
int height;
int leafCounter;
public:
// Constructor
MaxHeapTree(int n = 10) : elementSize(0), height(0), leafCounter(0) {
this->elementSize = elementSize;
this->height = height;
this->leafCounter = leafCounter;
HeapNode<Type> *array = new HeapNode<Type>[n];
}
// Destructor
~MaxHeapTree();
void arrayDisplay() {
cout << "Original array size: " << sizeof(array)/4 << endl;
}
// Returns the number of elements in the tree
int getSize() {
return elementSize;
}
// Returns the height of the tree
int getHeight() {
return height;
}
// Returns the number of leaves in the tree
int leaves() {
return leafCounter;
}
int countLines(const string fileName) {
string line;
int lineCount = 0;
ifstream myFile (fileName.c_str());
if (myFile.is_open()) {
while (getline(myFile, line)) {
lineCount++;
}
}
else {
cout << "Error opening file" << endl;
}
myFile.close();
return lineCount;
}
// Reads structure from a text file and builds a max heap
void buildTree(const string fileName) {
string line;
string key;
string value;
int lines = countLines(fileName);
int i = 0;
cout << "Lines: " << lines << endl;
HeapNode<Type> *newArray[lines];
cout << "Size of newArray: " << sizeof(newArray)/4 << endl;
ifstream myFile (fileName.c_str());
if (myFile.is_open()) {
while (getline(myFile, line)) {
key = line.substr(0, 1);
int x = atoi(key.c_str());
value = line.substr(1);
HeapNode<Type> *hNode = new HeapNode<Type>(x, value);
newArray[i] = hNode;
cout << "newArray[" << i << "] = ";
newArray[i]->displayNode();
i++;
}
}
else {
cout << "2 - Error opening file." << endl;
}
myFile.close();
}
};
#endif

How do you initialize template class members that uses other template classes?
In the same way you initialize members of non templates that don't use other templates.
when the tree is being initialized, I'm getting garbage data and not what I am initializing it to.
I was using MaxHeap<string> *heapTree1;
Well, there's your problem. Apparently you never created an instance of MaxHeap<string>.

Related

B+ tree insertion and searching

I'm trying to implement insertion and searching of information in files using b+tree, while doing so im getting an error as undefined reference
I've made changes from the original code whose link is given below only the main.cpp and header file has been changed
main.cpp
#include <iostream>
#include <vector>
//#include <algorithm>
#include <fstream>
#include <string>
//#include <filesystem>
#include "BPTree.h"
void insertionMethod(BPTree** bPTree) {
int rollNo;
int age, marks;
std::string name;
std::cout << "Please provide the rollNo: ";
std::cin >> rollNo;
std::cout << "\nWhat's the Name, Age and Marks acquired?: ";
std::cin >> name >> age >> marks;
std::string fileName = "DBFiles/";
fileName += std::to_string(rollNo) + ".txt";
FILE* filePtr = fopen(fileName.c_str(), "w");
std::string userTuple = name + " " + std::to_string(age) + " " + std::to_string(marks) + "\n";
fprintf(filePtr, userTuple.c_str());
//fclose(filePtr);
(*bPTree)->insert(rollNo, filePtr);
fclose(filePtr);
std::cout << "Insertion of roll No: " << rollNo << " Successful"<<std::endl;
}
void searchMethod(BPTree* bPTree) {
int rollNo;
std::cout << "What's the RollNo to Search? ";
std::cin >> rollNo;
bPTree->search(rollNo);
}
int main() {
bool flag = true;
int option;
int maxChildInt = 4, maxNodeLeaf = 3;
std::cout << "Please provide the value to limit maximum child Internal Nodes can have: ";
std::cin >> maxChildInt;
std::cout << "\nAnd Now Limit the value to limit maximum Nodes Leaf Nodes can have: ";
std::cin >> maxNodeLeaf;
BPTree* bPTree = new BPTree(maxChildInt, maxNodeLeaf);
std::cout<<bPTree->getMaxLeafNodeLimit()<<std::endl;
do {
std::cout << "\nPlease provide the queries with respective keys : " << std::endl;
std::cout << "\tPress 1: Insertion \n\tPress 2: Search<< std::endl;
std::cin >> option;
switch (option) {
case 1:
insertionMethod(&bPTree);
break;
case 2:
searchMethod(bPTree);
break;
default:
flag = false;
break;
}
}while (flag);
return 0;
}
BPTree.h
#include <iostream>
#include <vector>
#include <algorithm>
#include <fstream>
#include <string>
#ifndef NODE_H
#define NODE_H
class Node {
public:
bool isLeaf;
std::vector<int> keys;
Node* ptr2next;
union ptr {
std::vector<Node*> ptr2Tree; //Array of pointers to Children sub-trees for intermediate Nodes
std::vector<FILE*> dataPtr; // Data-Pointer for the leaf node
ptr(); // To remove the error !?
~ptr(); // To remove the error !?
} ptr2TreeOrData;
friend class BPTree; // to access private members of the Node and hold the encapsulation concept
public:
Node(){
this->isLeaf = false;
this->ptr2next = NULL;
}
};
class BPTree {
private:
int maxIntChildLimit; //Limiting #of children for internal Nodes!
int maxLeafNodeLimit; // Limiting #of nodes for leaf Nodes!!!
Node* root; Node* pparent = NULL; //Pointer to the B+ Tree root
void insertInternal(int x, Node** cursor, Node** child); //Insert x from child in cursor(parent)
Node** findParent(Node* cursor, Node* child){
if (cursor->isLeaf || cursor->ptr2TreeOrData.ptr2Tree[0]->isLeaf)
return NULL;
for (int i = 0; i < cursor->ptr2TreeOrData.ptr2Tree.size(); i++) {
if (cursor->ptr2TreeOrData.ptr2Tree[i] == child) {
pparent = cursor;
} else {
Node* tmpCursor = cursor->ptr2TreeOrData.ptr2Tree[i];
findParent(tmpCursor, child);
}
}
return &pparent;
}
public:
BPTree();
BPTree(int degreeInternal, int degreeLeaf){
this->maxIntChildLimit = degreeInternal;
this->maxLeafNodeLimit = degreeLeaf;
this->root = NULL;
}
int getMaxIntChildLimit();
int getMaxLeafNodeLimit()
{
return maxLeafNodeLimit;
}
void search(int key);
void insert(int key, FILE* filePtr);
};
#endif
Search and Insert code
The error im getting is
C:\Users\admin\AppData\Local\Temp\cctqZ0YA.o:insert.cpp:(.text$_ZN4NodeC1Ev[__ZN4NodeC1Ev]+0x20): undefined reference to `Node::ptr::ptr()'
collect2.exe: error: ld returned 1 exit status
I'm not so sure what Node::ptr::ptr() is could someone help out
The error message you get after deleting those declared but undefined constructor and destructor points to the actual problem. Why unions might need a constructor and destructor is better explained elsewhere, e.g. here and here.
You can get your code compiling by providing a trivial empty implementation.
ptr() {};
~ptr() {};

Unable to assign a range sub-string to an array of strings. c++

So I'm unable to create a substring cut using ranges. I am making an airport program where you feed the program a txt.file and it has to divide the lines I get from it into different strings. For instance, I have the following text data:
CL903 LONDON 41000 14.35 08906 //number of flight, destination, price, etc.
UQ5723 SYDNEY 53090 23.20 12986
IC5984 TORONTO 18030 04.45 03260
AM608 TOKYO 41070 18.45 11315
so the first string will be on the lines of this (variables are in Spanish):
numVuelo[n] = M[n].substr(0,5)
this line will work perfectly, but when I move to the next one (from 7 to 14), it tells me that it's out of range, even though It's between the 0 and 31st values of the length of the string.
M[n] gets all of the strings on the text, I'm using Codeblocks and a class style with header and all. I'll copy the code below...
This is my header Vuelo.h:
#ifndef VUELO_H
#define VUELO_H
#include <iostream>
#include <fstream>
#include <string>
#define NUM_FLIGHTS 10
using namespace std;
class Vuelo
{
public:
Vuelo(int N);
virtual ~Vuelo();
void setM();
void setNumVuelo(string _numVuelo, int n);
void setDestino(string _destino, int n);
void setPrecio(string _precio, int n);
private:
string M[NUM_FLIGHTS];
string numVuelo[NUM_FLIGHTS];
string destino[NUM_FLIGHTS+1]; //somehow "destino" doesn't work without the +1 but everything else does
float precio[NUM_FLIGHTS];
Then, on another code called Vuelo.cpp I have the following
#include "Vuelo.h"
Vuelo::Vuelo(int N)
{
M[N] = { };
numVuelo[N] = { };
destino[N] = { };
precio[N] = { };
}
Vuelo::~Vuelo()
{
//nope
}
void Vuelo::setM()
{
int c = 1;
string s;
ifstream F ("flights.txt");
if(F.is_open())
{
while (!F.eof())
{
getline(F,s);
M[c] = s;
cout << M[c] << endl;
c++;
}
//sets all values
for(c = 0; c < NUM_FLIGHTS; c++)
{
setNumVuelo(M[c],c);
setDestino(M[c],c);
setPrecio(M[c],c);
}
F.close();
}
else
{
cout << "ERROR document wasn't found" << endl;
}
}
void Vuelo::setNumVuelo(string _numVuelo, int n)
{
numVuelo[n]= _numVuelo.substr(0,5); //this works
cout << numVuelo[n] <<endl;
}
void Vuelo::setDestino(string _destino, int n)
{
destino[n] = _destino.substr(7, 13); //PROBLEM HERE
cout << destino[n] << " " << destino[n].length() << endl;
}
void Vuelo::setPrecio(string _precio, int n)
{
string p = _precio.substr(15,19); //PROBLEM HERE
precio[n] = atof(p.c_str());
cout << precio[n] <<endl;
}
And finally my main looks like this:
#include "Vuelo.h"
#include <iostream>
#include <fstream>
#include <string>
#define NUM_FLIGHTS 10
using namespace std;
int main()
{
cout << "Bienvenido, reserva tu vuelo!" << endl;
cout << "-----------------------------------" << endl;
Vuelo* flight = new Vuelo(NUM_FLIGHTS);
flight->setM();
return 0;
}
Thanks :)

C++ Unable to assign Character Array Variable to String Variable

I am in need of assistance.
I am trying to create a vector structure where the string contents inside of a char array get automatically assign to another STRING variable within the same structure.
After countless hours, I have not been able to figure it out. When I used function such as string(). It doesn't copy anything. I can't seem to assign char variable to string variable. Please advise.
#include <iostream>
#include <ctime>
#include <fstream>
#include <string>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
const int NAME_SIZE = 25;
struct tableInfo
{
char name2[NAME_SIZE];
string name = str(name2); // I need name string to equal name2 character variable
string info;
string link;
};
vector<tableInfo> table(6);
bool compareByWord(const tableInfo &lhs, const tableInfo &rhs);
int main()
{
cin.getline(table[0].name2, 51);
cin.getline(table[1].name2, 51);
cin.getline(table[2].name2, 51);
cin.getline(table[3].name2, 51);
cin.getline(table[4].name2, 51);
sort(table.begin(), table.end(), compareByWord);
cout << table[0].name << endl;
cout << table[1].name << endl;
cout << table[2].name << endl;
cout << table[3].name << endl;
cout << table[4].name << endl;
}
bool compareByWord(const tableInfo &lhs, const tableInfo &rhs)
{
unsigned int length = lhs.name.length();
if (rhs.name.length() < length)
length = rhs.name.length();
int sameLetters = 0;
for (unsigned int i = 0; i < length; ++i)
{
if (sameLetters == length)
return false;
if (tolower(lhs.name[i]) == tolower(rhs.name[i]))
{
++sameLetters;
continue;
}
return(lhs.name[i] < rhs.name[i]);
return(lhs.name[i] < rhs.name[i]);
}
return false;
}
If you want something to happen in a structure (or class), consider making sure it happens by using the constructor. You will need to change your vector so you can no longer default construct the struture, but that's ok.
This works, by enforcing the two fields contain identical data (not withstanding 25 no being long enough):
const int NAME_SIZE = 25;
struct tableInfo
{
tableInfo(char * whatever); //Make it so
char name2[NAME_SIZE];
string name;
string info;
string link;
};
tableInfo::tableInfo(char *whatever)
: name(whatever)
{
strncpy(name2, whatever, NAME_SIZE); //Now they match - unless whatever was too big
}
//vector<tableInfo> table(6);//no longer ok with the non-default constructor
bool compareByWord(const tableInfo &lhs, const tableInfo &rhs);
int main()
{
vector<tableInfo> table;
for (int i = 0; i < 5; ++i)
{
char name2[NAME_SIZE];
cin.getline(name2, 51); //Do you really mean 51?
// It's smaller than NAME_SIZE
table.emplace_back(name2);
}
sort(table.begin(), table.end(), compareByWord);
cout << table[0].name << endl;
cout << table[1].name << endl;
cout << table[2].name << endl;
cout << table[3].name << endl;
cout << table[4].name << endl;
}
How about doing like this:
struct tableInfo
{
char name2[NAME_SIZE];
string name;
string info;
string link;
tableInfo(const char* in_name)
{
memset(name2, 0, NAME_SIZE);
strncpy(name2, in_name, NAME_SIZE - 1);
name = string(name2);
}
};
How to use:
char tmp[NAME_SIZE];
cin.getline(tmp, 51);
table[0] = tableInfo(tmp);
I argue that you don't even need an array in the struct. Just use std::string. getline supports reading into a std::string and you can access individual characters using str[]. If you need to get a pointer to the data you can use str.c_str().
If you really need to use an array in the struct you can create a member function to return a std::string:
struct tableName {
char name[NAME_SIZE];
std::string info;
std::string link;
std::string nameString() const { return name; }
};

Link List - no operator '<<' matches

My c++ is really poor. Anyhow with the code snippet bellow why do I get a error on the << in the do while loop when outside of it I get no error. The error is: no operator "<<" matches these operands. However the string w picks up the word fine. I read somewhere I may have to overload it but why? And how would I over load it for a link list.
Thanks in advance.
void print()
{
HashTable *marker = headOne;
HashTable *inList;
for( int i = 0; i < tableSize; i++ )
{
cout << i << ": " << marker->number << endl;
if(marker->child != NULL)
{
inList = marker;
do
{
string w = inList->word;
cout << w << endl;
inList = inList->child;
}
while(inList != NULL);
}
marker = marker->next;
}//end for loop
}
In order to be able to cout a std::string you have to include:
#include <string>
#include <iostream>
This works:
// Missing includes and using
#include <string>
#include <iostream>
using namespace std;
// missing struct
struct HashTable {
HashTable* next;
HashTable* child;
string word;
int number;
};
// missing vars
HashTable ht;
HashTable* headOne = &ht;
int tableSize = 5;
// Unchanged
void print()
{
HashTable *marker = headOne;
HashTable *inList;
for( int i = 0; i < tableSize; i++ )
{
cout << i << ": " << marker -> number << endl;
if(marker->child != NULL)
{
inList = marker;
do
{
string w = inList -> word;
cout << w << endl;
inList = inList -> child;
}
while(inList != NULL);
}
marker = marker -> next;
}//end for loop
}
I read somewhere I may have to overload it but why?
Because there's no overload that matches your need.
And how would I over load it for a link list.
You can do this outside of your class or struct:
(where T is the type of the object that you want to print)
std::ostream& operator<<(std::ostream& os, const T& obj)
{
/* write obj to stream */
return os;
}
This is just an example that prints a vector:
std::ostream& operator<<(std::ostream& os, vector<int>& obj)
{
for (auto &i : obj)
os << i << " ";
return os;
}
Then I would be able to simply do this cout << n.vec; where n is the class object and vec the name of a vector of ints.

C++ string member variable not present in vector

I am creating a vector that contains pointers to a base class. In this vector I'm dynamically storing pointers to derived classes which contain some member variables, one of them being a string variable name.
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
bool hasDirection = false;
bool hasDiameter = false;
int direction;
float diameter;
int starDimension = 0;
int animalDimension = 0;
int fishDimension = 0;
class MovingObject
{
protected:
std::string name;
int direction;
float diameter;
int dimension;
float movingSpeed;
public:
std::string getName(){ return name;};
int getDirection(){ return direction;};
float getDiameter(){ return diameter;};
float getMovingSpeed(){ return movingSpeed;};
int getDimension(){ return dimension;};
void setName(std::string v){ name = v;};
void setDirection(int d){ direction = d;};
void setDiameter(float f){ diameter = f;};
void setMovingSpeed(float s){ movingSpeed = s;};
void setDimension (int d){ dimension = d;};
virtual void PrintContents()=0;
};
static std::vector<MovingObject*> data;
class starObject : public MovingObject
{
public:
void PrintContents()
{
std::cout << "(" << getName() << "," << getDiameter() << "," << getDirection() << ")";
}
};
class animalObject : public MovingObject
{
public:
void PrintContents()
{
std::cout << "(" << getName() << "," << getDiameter() << "," << getDirection() << ")";
}
};
class fishObject : public MovingObject
{
public:
void PrintContents()
{
std::cout << "(" << getName() << "," << getDiameter() << "," << getDirection() << ", [" << getDimension() << "], " << getMovingSpeed() << ")";
}
};
I later set all these member variables inside a main function. The problem is when I try to output the contents of the member variables, all of them show up except for the string name.
Now, I've checked to make sure that the string gets set before calling the PrintContent() method, and it shows that the value is in the vector. However, when I debug through the code, the value is no longer there, instead containing an empty string.
Could someone with better c++ knowledge explain to me why this is happening? This is the main class:
int main()
{
std::string type;
Reader reader;
while (!std::cin.eof())
{
try
{
std::string type;
std::cin >> type;
if (type =="int")
{
reader.ReadDirection();
}
else if (type =="float")
{
reader.ReadDiameter();
}
else if (type == "string")
{
std::string name;
std::cin >> name;
if (hasDirection && hasDiameter)
{
int dimension;
if (diameter > 0 && diameter < 10)
{
//fish
fishObject fish;
fish.setName(name);
fish.setDiameter(diameter);
fish.setDirection(direction);
dimension = fishDimension;
fishDimension += 50;
fish.setDimension(dimension);
fish.setMovingSpeed(0.1);
data.push_back(&fish);
}
else if (diameter >= 10 < 500)
{
//animal
animalObject animal;
animal.setName(name);
animal.setDiameter(diameter);
animal.setDirection(direction);
dimension = animalDimension;
animalDimension += 800;
animal.setDimension(dimension);
animal.setMovingSpeed(5.0);
data.push_back(&animal);
}
else if (diameter >=500)
{
//star
starObject star;
star.setName(name);
star.setDiameter(diameter);
star.setDirection(direction);
dimension = starDimension;
starDimension += 5000;
star.setDimension(dimension);
star.setMovingSpeed(30.0);
data.push_back(&star);
}
}
else
{
throw (IncompleteData(name));
}
}
}
catch (IncompleteData e)
{
std::cerr << "No diameter or direction given for object " << e.objectName << "\n";
}
}
The objects you push to the data vector are local because they are declared inside if/else blocks (see the declarations of fish and animal).
When you push the address of such an object to the vector, it will continue to point to the local object, which ceases to exist at the end of the local scope. You need to create objects that live beyond the local scope. One way of doing this is to create copies of the local objects on the heap and push those to the vector:
data.push_back(new fishObject(fish));
Of course this means that you get a memory leak unless you make sure you explicitly delete the elements of the vector some time before the end of the program. The usual recommendation to avoid having to think of this is to use a vector of std::unique_ptr<MovingObject> instead of a vector of naked pointers.