I currently have a Person class, and have created a PersonList class that extends List, specifically for objects of type Person. When I instantiate a new PersonList I get one error that stops the entire build from happening successfully:
error C2678: binary '==' : no operator found which takes a left-hand operand of type 'Person' (or there is no acceptable conversion) c:\program files\microsoft visual studio 11.0\vc\include\xutility 3186 1 ConsoleApplication3
Here is the PersonList class:
#pragma once
#include<iostream>
#include<sstream>
#include<string>
#include<algorithm>
#include "linearList.h"
#include "myExceptions.h"
#include "changeLength1D.h"
#include <Person.h>
using namespace std;
template<class Person>
class PersonList: public linearList<Person>
{
public:
PersonList(int initialCapacity = 10);
PersonList(const PersonList<Person>&);
~PersonList() {delete [] element;}
bool empty() const {return listSize == 0;}
int size() const {return listSize;}
Person& get(int theIndex) const;
int indexOf(const Person& theElement) const;
void erase(int theIndex);
void insert(int theIndex, const Person& theElement);
void output(ostream& out) const;
// additional method
int capacity() const {return arrayLength;}
protected:
void checkIndex(int theIndex) const;
// throw illegalIndex if theIndex invalid
Person* element; // 1D array to hold list elements
int arrayLength; // capacity of the 1D array
int listSize; // number of elements in list
};
template<class Person>
PersonList<Person>::PersonList(int initialCapacity)
{// Constructor.
if (initialCapacity < 1)
{ostringstream s;
s << "Initial capacity = " << initialCapacity << " Must be > 0";
throw illegalParameterValue(s.str());
}
arrayLength = initialCapacity;
element = new Person[arrayLength];
listSize = 0;
}
template<class Person>
PersonList<Person>::PersonList(const PersonList<Person>& theList)
{// Copy constructor.
arrayLength = theList.arrayLength;
listSize = theList.listSize;
element = new Person[arrayLength];
copy(theList.element, theList.element + listSize, element);
}
template<class Person>
void PersonList<Person>::checkIndex(int theIndex) const
{// Verify that theIndex is between 0 and listSize - 1.
if (theIndex < 0 || theIndex >= listSize)
{ostringstream s;
s << "index = " << theIndex << " size = " << listSize;
throw illegalIndex(s.str());
}
}
template<class Person>
Person& PersonList<Person>::get(int theIndex) const
{// Return element whose index is theIndex.
// Throw illegalIndex exception if no such element.
checkIndex(theIndex);
return element[theIndex];
}
template<class Person>
int PersonList<Person>::indexOf(const Person& theElement) const
{// Return index of first occurrence of theElement.
// Return -1 if theElement not in list.
// search for theElement
int theIndex = (int) (find(element, element + listSize, theElement)
- element);
// check if theElement was found
if (theIndex == listSize)
// not found
return -1;
else return theIndex;
}
template<class Person>
void PersonList<Person>::erase(int theIndex)
{// Delete the element whose index is theIndex.
// Throw illegalIndex exception if no such element.
checkIndex(theIndex);
// valid index, shift elements with higher index
copy(element + theIndex + 1, element + listSize,
element + theIndex);
element[--listSize].~Person(); // invoke destructor
}
template<class Person>
void PersonList<Person>::insert(int theIndex, const Person& theElement)
{// Insert theElement so that its index is theIndex.
if (theIndex < 0 || theIndex > listSize)
{// invalid index
ostringstream s;
s << "index = " << theIndex << " size = " << listSize;
throw illegalIndex(s.str());
}
// valid index, make sure we have space
if (listSize == arrayLength)
{// no space, double capacity
changeLength1D(element, arrayLength, 2 * arrayLength);
arrayLength *= 2;
}
// shift elements right one position
copy_backward(element + theIndex, element + listSize,
element + listSize + 1);
element[theIndex] = theElement;
listSize++;
}
template<class Person>
void PersonList<Person>::output(ostream& out) const
{// Put the list into the stream out.
copy(element, element + listSize, ostream_iterator<Person>(cout, " "));
}
// overload <<
template <class Person>
ostream& operator<<(ostream& out, const PersonList<Person>& x)
{x.output(out); return out;}
The Person Class:
#pragma once
#include <string>
using namespace std;
class Person
{
public:
Person(string firstName, string lastName, string birthday, string hometown);
Person(void);
~Person(void);
string name;
string birthday;
string hometown;
};
The same thing happens in an arrayList class I tried using earlier. Is there a way to get it so I can simply store person objects in an ArrayList type structure?
Your function indexOf() contains a call to STL's std::find() algorithm, which internally performs comparisons between pairs of values to determine if the element passed as a third argument is contained in the range defined by the first two arguments.
To perform this comparison, std::find() uses the == operator. However, no operator == has been defined for objects of type Person.
In order to solve the problem, you must overload the comparison operator == for instances of Person. You can do it, for instance, this way:
class Person
{
...
public:
friend bool operator == (Person const& p1, Person const& p2)
{
// Perform the comparison and return "true" if the objects are equal
return (p1.name == p2.name) && ...
}
};
Related
I am learning templates and am struggling to set up my put method without compiler errors. Can someone point me in the right direction? The commented sections are not implemented yet, but based on an Integer-key, String-value implementation.
The concrete error I am having: Severity Code Description Project File Line Suppression State
Error C2923 'HashTable<int,std::string>::HashItem': 'key' is not a valid template type argument for parameter 'Key'
#pragma once
#include <cmath>
#include <iostream>
#include <list>
using namespace std;
template<typename Key, typename Value>
class HashTable
{
template<typename Key, typename Value>
class HashItem {
public:
Key key;
Value value = nullptr;
bool operator==(const HashItem& hi) const { return key == hi.key && value == hi.value; }
HashItem(const Key& k, const Value& v)
: key(k), value(v) {}
// for part b)
HashItem& operator=(const Value& v) {
this->value = v;
return *this;
}
operator string() { return this->value; }
};
list<HashItem<Key, Value>>* table;
int current_total = 0;
float FILL_LEVEL = 0.8; // Füllgrad, between 0 and 1
// not const:
int CAPACITY = 100; // default value
// for hash functions/preparing for use with strings:
const int PRIME_CONST = 31;
int hash_function(string key);
int hash_function(int key);
// std::hash?
void rehash();
public:
HashTable() {
cout << "ht cstructed, intitial_capacity is (default:) " << CAPACITY << endl;
}
HashTable(int initial_capacity) {
cout << "ht cstructed, intitial_capacity is " << initial_capacity << endl;
CAPACITY = initial_capacity;
}
//// RULE OF THREE
//// copy ctor
//HashTable(HashTable& const ht);
//// destructor
//~HashTable();
//// (copy) assignment operator
//HashTable& operator=(HashTable& const ht);
//// RULE OF FIVE
//// move ctor
//HashTable(HashTable&& ht); // && -> rvalue
//// move assignment operator
//HashTable& operator=(HashTable&& ht);
//// Hash Table operations
void put(Key key, Value value) {
// allocate memory with first put
if (current_total == 0)
table = new list<HashItem<key, value>>[CAPACITY];
HashItem<key, value>* hi = new HashItem(key, value);
int hash = hash_function(key);
if (find(table[hash].begin(), table[hash].end(), *hi) == table[hash].end()) {
// only put if not already in list
table[hash].push_back(*hi);
}
current_total++;
//cout << "current total is " << current_total << " of " << FILL_LEVEL * CAPACITY << endl;
// rehash check
if (current_total > (FILL_LEVEL * CAPACITY)) {
rehash();
//cout << "fill level reached: rehashed" << endl;
}
}
//void remove(int key, string value);
//string get(int key);
//// for part b)
//HashItem& get_item(int key) {
// int list_index = hash_function(key); // list_index = hash_code
// if (!table[list_index].empty()) {
// for (auto &list_item : table[list_index]) {
// if (key == list_item.key) {
// return list_item;
// }
// }
// }
// HashItem hi(key, "");
// return hi;
//}
//friend ostream& operator<<(ostream& os, const HashTable& ht);
//void clear();
//bool contains(int key);
//bool contains_value(string value);
//// fill levels
//void set_fill_level(float new_level);
//float get_fill_level();
//// b)
//// Overloading [] operator to access elements in array style
//HashItem& operator[] (int key) {
// if (this != nullptr)
// return this->get_item(key);
// HashItem hi(key, "");
// // stand-in hash item in case not in hash table
// return hi;
//}
};
Call in my main.cpp:
#include <iostream>
#include "HashTable.h"
using namespace std;
#define DEBUG(X) cout << (#X) << " = " << (X) << endl
HashTable<int, string> ht;
void put_test() {
cout << "--------------- put test ----------------------------------" << endl;
ht.put(10, "test");
}
int main() {
put_test();
}
For a project I'm working on in school I have to insert a pointer to one object into two BSTs. One BST is sorted by the APN(a unique key), and the other is sorted by price(non unique). We are using templates, so I asked my professor how to accomplish this and she said to use function pointers. When I tried to do so, I came across a few errors I don't know how to resolve.
The object is defined as
class House
{
private:
string APN; // Unique key
int price; // Non-unique key
string address;
int bedrooms;
double bathrooms;
int sqFt;
}
In main, after I've created the object I try to run.
uniqueTree->insert(newHouse, comparePrimaryKey);
nonUniqueTree->insert(newHouse, compareSecondaryKey);
Where each function is defined as
int comparePrimaryKey(const House* &left, const House* &right)
{
if(left->getAPN() < right->getAPN())
return -1;
else
return 1;
}
int compareSecondaryKey(const House* &left, const House* &right)
{
if(left->getPrice() < right->getPrice()) // right > left
return -1;
else // right < left
return 1;
}
But I get an error saying
"Cannot initialize a parameter of type 'int (*)(House *const &, House *const &)
with an lvalue of type 'int (const House *&, const House *&)'"
There is a BinaryNode object pointer called rootPtr in the Binary Tree file, and insert is defined as a purely virtual function.
BinaryNode<ItemType>* rootPtr;
virtual bool insert(const ItemType & newData, int compare(const
ItemType&, const ItemType&)) = 0;
The binary node class:
template<class T>
class BinaryNode
{
private:
T item; // Data portion
BinaryNode<T>* leftPtr; // Pointer to left child
BinaryNode<T>* rightPtr; // Pointer to right child
public:
// constructors
BinaryNode(const T & anItem) {item = anItem; leftPtr = 0; rightPtr = 0;}
BinaryNode(const T & anItem,
BinaryNode<T>* left,
BinaryNode<T>* right) {item = anItem; leftPtr = left; rightPtr = right;}
// mutators
void setItem(const T & anItem) {item = anItem;}
void setLeftPtr(BinaryNode<T>* left) {leftPtr = left;}
void setRightPtr(BinaryNode<T>* right) {rightPtr = right;}
// accessors
T getItem() const {return item;}
BinaryNode<T>* getLeftPtr() const {return leftPtr;}
BinaryNode<T>* getRightPtr() const {return rightPtr;}
bool isLeaf() const {return (leftPtr == 0 && rightPtr == 0);}
};
In the BST file, insert is defined as
template<class ItemType>
bool BinarySearchTree<ItemType>::insert(const ItemType &newEntry, int
compare(const ItemType &, const ItemType &))
{
BinaryNode<ItemType>* newNodePtr = new BinaryNode<ItemType>(newEntry);
BinaryTree<ItemType>::rootPtr = _insert(BinaryTree<ItemType>::rootPtr,
newNodePtr, compare(newNodePtr->getItem(), BinaryTree<ItemType>::rootPtr()->getItem()));
return true;
}
I am also getting an error at the BinaryTree::rootPtr line saying that
Called object type 'BinaryNode<House *> *' is not a function or function pointer
here is a simple program that solve your first problem, i added the definitions of some function so that i can test your class and functions.
#include <iostream>
#include <string>
class House
{
private:
std::string APN; // Unique key
int price; // Non-unique key
std::string address;
int bedrooms;
double bathrooms;
int sqFt;
public:
House(std::string apn, int prix)
{
APN = apn;
price = prix;
}
std::string getAPN(void)
{
return APN;
}
int getPrice()
{
return price;
}
};
int comparePrimaryKey( House *const &left, House *const &right)
{
if(left->getAPN() < right->getAPN())
return -1;
else
return 1;
}
int compareSecondaryKey( House *const &left, House *const &right)
{
if(left->getPrice() < right->getPrice()) // right > left
return -1;
else // right < left
return 1;
}
// Main function for the program
int main( )
{
int PrimaryKey =0;
int SecondaryKey=0;
House right("droite",2050);
House left("gauche",2000);
PrimaryKey = comparePrimaryKey(&left, &right);
SecondaryKey = compareSecondaryKey(&left, &right);
std::cout<< PrimaryKey << std::endl;
std::cout << SecondaryKey << std::endl;
std::system("PAUSE");
return 0;
}
In my project, I am using a header file for an arrayList. During the main method, I initialize an object of type arrayList where FriendToken is another class defined in my project. However, this gives me quite a few errors while compiling arrayList.h. Apparently, I cannot use the built-in copy method and the operator == is unrecognized for an object of type FriendToken. Should I overload the == operator for FriendToken and if so, how should I do that?
Both errors are marked in the body ArrayList.h.
ArrayList.h:
#ifndef arrayList_h
#define arrayList_h
#include "linearList.h"
#include <iostream>
#include <fstream>
#include <ostream>
using namespace std;
template<class T>
class arrayList : public linearList<T>
{
public:
// constructor, copy constructor and destructor
arrayList(int initialCapacity = 10);
arrayList(const arrayList<T>&);
~arrayList() {delete [] element;}
// ADT methods
bool empty() const {return listSize == 0;}
int size() const {return listSize;}
T& get(int theIndex) const;
int indexOf(const T& theElement) const;
void erase(int theIndex);
void insert(int theIndex, const T& theElement);
void output(ostream& out) const;
void changeLength1D(T*& a, int oldLength, int newLength);
// additional method
int capacity() const {return arrayLength;}
protected:
void checkIndex(int theIndex) const;
// throw illegalIndex if theIndex invalid
T* element; // 1D array to hold list elements
int arrayLength; // capacity of the 1D array
int listSize; // number of elements in list
};
template<class T>
arrayList<T>::arrayList(int initialCapacity)
{
// Constructor.
arrayLength = initialCapacity;
element = new T[arrayLength];
listSize = 0;
}
template<class T>
arrayList<T>::arrayList(const arrayList<T>& theList)
{
// Copy constructor.
arrayLength = theList.arrayLength;
listSize = theList.listSize;
element = new T[arrayLength];
copy(theList.element, theList.element + listSize, element);
}
template<class T>
void arrayList<T>::checkIndex(int theIndex) const
{
// Verify that theIndex is between 0 and
// listSize - 1.
if (theIndex < 0 || theIndex >= listSize)
{
cout << "index = " << theIndex << " size = "
<< listSize;
}
}
template<class T>
T& arrayList<T>::get(int theIndex) const
{
// Return element whose index is theIndex.
// Throw illegalIndex exception if no such
// element.
checkIndex(theIndex);
return element[theIndex];
}
template<class T>
int arrayList<T>::indexOf(const T& theElement)const
{
// Return index of first occurrence of theElement.
// search for theElement
int theIndex = (int) (find(element, element
+ listSize, theElement) - element);
// check if theElement was found
if (theIndex == listSize)
return -1; // not found
else return theIndex;
}
template<class T>
void arrayList<T>::erase(int theIndex)
{// Delete the element whose index is theIndex.
checkIndex(theIndex);
// valid index, shift elements with higher index
//PROBLEM********************************************
copy(element + theIndex + 1, element + listSize,element + theIndex);
element[--listSize].~T(); // invoke destructor
}
template<class T>
void arrayList<T>::insert(int theIndex, const T& theElement)
{
// Insert theElement.
if (theIndex < 0 || theIndex > listSize)
{// invalid index
// code to throw an exception comes here
}
// valid index, make sure we have space
if (listSize == arrayLength)
{
// no space, double capacity
changeLength1D(element, arrayLength,
2 * arrayLength);
arrayLength *= 2;
}
// shift elements right one position
//PROBLEM***************************************
copy_backward(element + theIndex, element + listSize, element + listSize + 1);
element[theIndex] = theElement;
listSize++;
}
template<class T>
void arrayList<T>::output(ostream& out) const
{
// Put the list into the stream out.
copy(element, element + listSize, ostream_iterator<T>(out, " "));
}
template <class T>
ostream& operator<<(ostream& out, const arrayList<T>& x)
{x.output(out); return out;}
template<class T>
void changeLength1D(T*& a, int oldLength, int newLength)
{
if (newLength < 0)
throw illegalParameterValue();
T* temp = new T[newLength];
// new array
int number = min(oldLength, newLength);
// number to copy
copy(a, a + number, temp);
delete [] a;
// deallocate old memory
a = temp;
}
#endif
FriendToken.h
#ifndef FriendToken_h
#define FriendToken_h
#include <string>
using namespace std;
class FriendToken
{
private:
string birthDate, name, homeTown;
public:
FriendToken(string birthDate = "01/01", string name = "John, Smith", string homeTown = "New York");
string getBirthDate();
string getName();
string getHomeTown();
bool equals(FriendToken a);
};
#endif
FriendToken.cpp
#include "FriendToken.h"
#include <string>
using namespace std;
FriendToken::FriendToken(string birthDate, string name, string homeTown)
{
this->birthDate = birthDate;
this->name = name;
this->homeTown = homeTown;
}
string FriendToken::getBirthDate()
{
return birthDate;
}
string FriendToken:: getName()
{
return name;
}
string FriendToken::getHomeTown()
{
return homeTown;
}
bool FriendToken::equals(FriendToken a)
{
return (name == a.getName()) && (homeTown == a.getHomeTown()) && (birthDate == a.getBirthDate());
}
It's hard to tell without the compiler errors.
Either way, this is how you overload the operator.
template<typename T>
bool arrayList::operator== (const arrayList<T>& theList)
{
// Compare the values, and return a bool result.
}
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I'm working on implementing a chain data structure, using a specific set of pre-made templates. Upon compilation, I'm receiving the error in the title.
arrayList.h:
#ifndef arrayList_h
#define arrayList_h
#include <iostream>
#include "linearList.h"
using namespace std;
template<class T>
class arrayList : public linearList<T>{
public:
//constructor, copy constructor, destructor
arrayList(int initialCapacity = 10);
arrayList(const arrayList<T>&);
~arrayList() {delete [] element;};
//ADT methods
bool empty() const {return listSize == 0;};
int size() const {return listSize;};
T& get(int theIndex) const;
int indexOf(const T& theElement) const;
void erase(int theIndex);
void insert(int theIndex, const T& theElement);
void output(ostream& out) const;
//additional method
int capacity() const {return arrayLength;};
protected:
void checkIndex(int theIndex) const;
//throw illegalIndex if theIndex is invalid
T* element; //1D array to hold list elements
int arrayLength; //capacity of 1D array
int listSize; //number of elements in list
};
#endif
chain.h:
#ifndef chain_h
#define chain_h
#include <iostream>
#include "linearList.h"
#include "chainNode.h"
using namespace std;
template<class T>
class chain : public linearList<T>{
public:
// constructor and destructor
chain(int initialCapacity = 10);
//chain(const chain<T>&);
~chain();
// ADT methods
bool empty() const {return listSize == 0;}
int size() const {return listSize;}
T& get(int theIndex) const;
int indexOf(const T& theElement) const;
void erase(int theIndex);
void insert(int theIndex, const T& theElement);
void output(ostream& out) const;
protected:
void checkIndex(int theIndex) const;
chain<T>* firstNode;
int listSize;
};
#endif
chainNode.h:
#ifndef chainNode_h
#define chainNode_h
#include <iostream>
template <class T>
struct chainNode
{
// data members
T element;
chainNode<T> *next;
// methods
chainNode() {}
chainNode(const T& element)
{this->element = element;}
chainNode(const T& element, chainNode<T>* next)
{this->element = element;
this->next = next;}
};
#endif
chain.cpp:
#include "chain.h"
#include "person.h"
using namespace std;
template<class T>
chain<T>::chain(int initialCapacity){
// Constructor.
/*if (initialCapacity < 1){
ostringstream s;
s << "Initial capacity = "
<< initialCapacity << " Must be > 0";
throw illegalParameterValue(s.str());
}*/
firstNode = NULL;
listSize = 0;
}
template<class T>
chain<T>::~chain(){
// Chain destructor. Delete all nodes
// in chain.
while (firstNode != NULL){
// delete firstNode
chainNode<T>* nextNode = firstNode->next;
delete firstNode;
firstNode = nextNode;
}
}
template<class T>
T& chain<T>::get(int theIndex) const{
// Return element whose index is theIndex.
checkIndex(theIndex);
// move to desired node
chainNode<T>* currentNode = firstNode;
for (int i = 0; i < theIndex; i++)
currentNode = currentNode->next;
return currentNode->element;
}
template<class T>
int chain<T>::indexOf(const T& theElement) const{
// search the chain for theElement
chainNode<T>* currentNode = firstNode;
int index = 0; // index of currentNode
while (currentNode != NULL && currentNode->element != theElement){
// move to next node
currentNode = currentNode->next;
index++;
}
// make sure we found matching element
if (currentNode == NULL)
return -1;
else
return index;
}
template<class T>
void chain<T>::erase(int theIndex){
checkIndex(theIndex);
chainNode<T>* deleteNode;
if (theIndex == 0){
// remove first node from chain
deleteNode = firstNode;
firstNode = firstNode->next;
}
else{
// use p to get to beforeNode
chainNode<T>* p = firstNode;
for (int i = 0; i < theIndex - 1; i++)
p = p->next;
deleteNode = p->next;
p->next = p->next->next;
}
listSize--;
delete deleteNode;
}
template<class T>
void chain<T>::insert(int theIndex, const T& theElement){
if (theIndex < 0 || theIndex > listSize){
// THROW ILLEGAL EXCEPTION
}
if (theIndex == 0) // insert at front
firstNode = new chainNode<T>(theElement, firstNode);
else{
// find predecessor of new element
chainNode<T>* p = firstNode;
for (int i = 0; i < theIndex - 1; i++)
p = p->next;
// insert after p
p->next = new chainNode<T>(theElement, p->next);
}
listSize++;
}
Person.h:
#ifndef Person_h
#define Person_h
#include <string>
#include <sstream>
using namespace std;
class Person{
public:
//Variables
string birthdate;
string first_name;
string last_name;
string hometownID;
string hometownName;
string userID;
string name;
//Constructors
Person();
Person(string birthdate, string first_name, string last_name, string hometownID, string hometownName, string userID);
//Methods
string getBirthdate();
void setBirthdate(string birthdate);
string getFirst_name();
void setFirst_name(string first_name);
string getLast_name();
void setLast_name(string last_name);
string getName();
void setName(string name);
string getHometownID();
void setHometownID(string hometownID);
string getHometownName();
void setHometownName(string hometownName);
string getUserID();
void setUserID(string userID);
int compare(Person& p, int criteria);
//Comparisons
friend bool operator== (Person p1, Person p2);
friend bool operator!= (Person &p1, Person &p2);
friend bool operator> (Person &p1, Person &p2);
friend bool operator>= (Person &p1, Person &p2);
friend bool operator< (Person &p1, Person &p2);
friend bool operator<= (Person &p1, Person &p2);
friend ostream& operator<<(ostream& os, const Person& p);
};
#endif
Person.cpp: I've cut this down quite a bit. I currently don't have anything having to do with Node within this.
#include "Person.h"
#include <sstream>
#include <string>
using namespace std;
Person::Person(){
birthdate = "";
name = "";
hometownID = "";
hometownName = "";
userID = "";
}
Person::Person(string birthdate, string first_name, string last_name, string hometownID, string hometownName, string userID){
this->birthdate = birthdate;
this->first_name = first_name;
this->last_name = last_name;
this->hometownID = hometownID;
this->hometownName = hometownName;
this->userID = userID;
name = last_name+ ", " +first_name;
}
//mostly get/set methods after here, nothing having to do with node.
main.cpp:
#include "arrayList.cpp"
#include "block_allocator.h"
#include "chain.cpp"
#include "chainNode.h"
#include "json.h"
#include "linearList.h"
#include "Person.h"
#include <string>
#include <fstream>
#include <streambuf>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <time.h>
using namespace std;
//ArrayList helper methods
arrayList<Person> arrayListStructure(string fileName);
int arrayListSort(int criteria, arrayList<Person>* list);
void arrayListReverseSort(int criteria, arrayList<Person>* list);
int arrayListFlip(arrayList<Person>* list);
//Chain helper methods
chain<Person> chainStructure(string fileName);
//Hashtable helper methods
int main(int argc, const char * argv[]){
//get fileName
cout << "Please enter a filename:" << endl;
string fileName;
cin >> fileName;
//get data structure type
cout << "Please choose a data structure:" << endl;
cout << " 1. Arraylist" << endl;
cout << " 2. Chain" << endl;
cout << " 3. Hashtable" << endl;
int dataStructure;
cin >> dataStructure;
cout << "Please choose a criteria:" << endl;
cout << " 1. Name" << endl;
cout << " 2. Birthday" << endl;
cout << " 3. Location" << endl;
int criteria;
cin >> criteria;
arrayList<Person> friends;
chain<Person> friendChain;
//parse file into data structure
switch(dataStructure){
case 1: //Arraylist
//edited out, irrelevant
/*case 2:
//Chain
//code goes here
/*switch(criteria){
case 1: //Name
case 2: //Birthday
case 3: //Location
}
break;*/
/*case 3:
//Hashtable
//code goes here
break;
*/
}
}
//Helper methods for chain
chain<Person> chainStructure(string fileName){
//create initial (empty) chain
chain<Person> friends;
//open input file
ifstream fileInput(fileName);
//turn input stream into string
string inputStr((istreambuf_iterator<char>(fileInput)), istreambuf_iterator<char>());
//parse file content into json object
char *errorPos = 0;
char *errorDesc = 0;
int errorLine = 0;
block_allocator allocator(1 << 10);
json_value *root = json_parse(const_cast<char*>(inputStr.c_str()), &errorPos, &errorDesc, &errorLine, &allocator);
//Take value of first element
json_value *list = root->first_child;
//Outer loop addresses each friend's JSON object
for(json_value *it = list->first_child; it; it = it->next_sibling){
string first_name, last_name, birthdate, hometownID, hometownName, userID;
//Inner loop looks at each key/value pair within each friend object
for(json_value *friendKeys = it->first_child; friendKeys; friendKeys = friendKeys->next_sibling){
//grab first name
if(!string(friendKeys->name).compare("first_name")){
first_name = friendKeys->string_value;
}
//grab last name
else if(!string(friendKeys->name).compare("last_name")){
last_name = friendKeys->string_value;
}
//grab birthday and trim to 5 characters
else if(!string(friendKeys->name).compare("birthday")){
birthdate = friendKeys->string_value;
birthdate = birthdate.substr(0, 5);
}
//grab hometown info
else if(!string(friendKeys->name).compare("hometown")){
for(json_value *hometownKeys = friendKeys->first_child; hometownKeys; hometownKeys = hometownKeys->next_sibling){
if(!string(hometownKeys->name).compare("id")){
hometownID = hometownKeys->string_value;
}
if(!string(hometownKeys->name).compare("name")){
hometownName = hometownKeys->string_value;
}
}
}
//grab userID
else if(!string(friendKeys->name).compare("id")){
userID = friendKeys->string_value;
}
}
if(birthdate != "" && first_name != "" && last_name != "" && hometownID != "" && hometownName != "" && userID != ""){
//Create new Person in chain
Person person(birthdate, first_name, last_name, hometownID, hometownName, userID);
friends.insert(friends.size(), person);
}
}
//return friends;
return friends;
}
//Helper methods for hashtable
So I know this is a huge wall of text, but I'm really not sure where this disconnect is, and I didn't want to provide too little information. Any help or advice would be greatly appreciated, as I'm very new to C++, and even more inexperienced with using the template system.
EDIT: linearList.h:
#ifndef linearList_h
#define linearList_h
#include <iostream>
using namespace std;
template<class T>
class linearList
{
public:
virtual ~linearList() {};
virtual bool empty() const = 0;
// return true iff list is empty
virtual int size() const = 0;
// return number of elements in list
virtual T& get(int theIndex) const = 0;
// return element whose index is theIndex
virtual int indexOf(const T& theElement) const = 0;
// return index of first occurence of theElement
virtual void erase(int theIndex) = 0;
// remove the element whose index is theIndex
virtual void insert(int theIndex, const T& theElement) = 0;
// insert theElement so that its index is theIndex
virtual void output(ostream& out) const = 0;
// insert list into stream out
};
#endif
In chain.h, the chain<T> template has this for a member:
chain<T>* firstNode;
I'm pretty sure that should be:
chainNode<T>* firstNode;
There may be other errors (or maybe not), but that appears the likely one causing your current issue that is the subject of this question.
Side Bar: This thing needs a serious refactor to use the containers and algorithms from the standard library (std::vector<T>, std::list<T>, etc...) Just consider it.
I am trying to create custom array indexed from 1 using subscript operator. Getting value works fine, but I have no clue, why assign using subscript operator doesn't work.
class CEntry {
public:
CKey key;
CValue val;
CEntry(const CKey& key, const CValue& val) {
this->key = key;
this->val = val;
}
CEntry& operator= (const CEntry& b) {
*this = b;
return *this;
};
};
...
class EntriesArray {
public:
CEntry **entries;
int length;
EntriesArray(int length) {
this->length = length;
entries = new CEntry*[length];
int i;
for (i = 0; i < length + 1; i++) {
entries[i] = NULL;
}
};
CEntry& operator[] (const int index) {
if (index < 1 || index > length) {
throw ArrayOutOfBounds();
}
return *entries[index - 1];
};
};
Constructs array this way
EntriesArray a(5);
This works
a.entries[0] = new CEntry(CKey(1), CValue(1));
cout << a[1].val.value << endl;
This doesn't work
a[1] = new CEntry(CKey(1), CValue(1));
EDIT:
Using
CEntry *operator=( CEntry *orig)
it compiles okey, but gdb stops at
No memory available to program now: unsafe to call malloc warning: Unable to restore previously selected frame
with backtrace
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00007fff5f3ffff8
0x00000001000013c8 in CEntry::operator= (this=0x0, orig=0x1001008d0) at /Users/seal/Desktop/efa du2_pokus2/efa du2_pokus2/main.cpp:20
20 /Users/seal/Desktop/efa du2_pokus2/efa du2_pokus2/main.cpp: No such file or directory.
in /Users/seal/Desktop/efa du2_pokus2/efa du2_pokus2/main.cpp
At first... This:
CEntry& operator= (const CEntry& b) {
*this = b;
return *this;
};
Shouldn't work (this should result in recursive call of operator=).
The second thing is that you're trying to assign CEntry * to CEntry, this would work if you had CEntry *operator=( CEntry *orig), but I think this is bad coding practice.
This question may be related to this one.
I tried to fix your code; I believe that this is what you were trying to do:
(tested this code on g++ 5.3.0)
#include <iostream>
#include <stdexcept>
#include <string>
// Some implementation for CKey and CValue:
typedef int CKey;
struct CValue {
int value;
CValue(int value=0) : value(value) {}
};
class CEntry {
public:
CKey key;
CValue val;
CEntry(): key(0), val(0) {}
CEntry(const CKey& key, const CValue& val): key(key), val(val) {}
CEntry& operator= (const CEntry& b) {
this->key = b.key;
this->val = b.val;
return *this;
};
};
class EntriesArray {
public:
CEntry *entries;
int length;
EntriesArray(int length) {
this->length = length;
entries = new CEntry[length];
};
CEntry& operator[] (const int index) {
if (index < 1 || index > length) {
throw std::domain_error("out of bounds!");
}
return entries[index - 1];
};
};
int main(int argc, char* argv[]) {
using namespace std;
EntriesArray a(5);
// This works
a.entries[0] = CEntry(CKey(1), CValue(1));
cout << a[1].val.value << endl;
// This doesn't work
a[1] = CEntry(CKey(2), CValue(2));
cout << a[1].val.value << endl;
}
Also you might want to use a[1] as a[1].val.value e.g.:
cout << a[1] << endl;
To do this just add to this line to cEntry:
operator int() { return val.value; }
I hope it helps.
You could try replacing
CEntry& operator[] (const int index) {
if (index < 1 || index > length) {
throw ArrayOutOfBounds();
}
return *entries[index - 1];
};
with
void Add(const int index, CEntry *pEntry) {
if (index < 1 || index > length) {
throw ArrayOutOfBounds();
}
entries[index - 1] = pEntry;
};
but since you are now storing references to objects allocated on the heap (with new) you will need a destructor ~EntriesArray() to delete them all.
Because EntriesArray::operator[] returns a CEntry &, but new CEntry returns a CEntry *.
Perhaps you want a[1] = CEntry(CKey(1), CValue(1))? (no new.)
By the way, your current definition of CEntry::operator= will lead to a stack overflow.
This
return *entries[index - 1];
dereferences a NULL pointer.
You want the pointer itself to be overwritten by a[1] = new CEntry(CKey(1), CValue(1));, not the pointed-to-value.
Try this:
class EntriesArray
{
public:
int length;
CEntry **entries;
EntriesArray( int length ) : length(length), entries(new CEntry*[length]())
{
}
// defaulted special member functions are inappropriate for this class
EntriesArray( const EntriesArray& ); // need custom copy-constructor
~EntriesArray(); // need custom destructor
EntriesArray& operator=(const EntriesArray&); // need custom assignment-operator
CEntry*& operator[] (const int index) {
if (index < 1 || index > length) {
throw ArrayOutOfBounds();
}
return entries[index - 1];
}
};
Further to my comment above:
To make it work with writing new values, you probably need something like this
(I haven't double checked for off by one or ptr vs reference stuff)
CEntry& operator[] (const int index) {
if (index < 1) {
throw ArrayOutOfBounds();
}
// Add default elements between the current end of the list and the
// non existent entry we just selected.
//
for(int i = length; i < index; i++)
{
// BUG is here.
// We don't actually know how "entries" was allocated, so we can't
// assume we can just add to it.
// We'd need to try to resize entries before coming into this loop.
// (anyone remember realloc()? ;-)
entries[i] = new CEntry();
}
return *entries[index - 1];
};