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;
}
Related
There are many questions like this but after looking at some cases, I guess this question is case-specific so I post my code and pointed out where the problem takes place may you be patient reading my code?
uniBTree.h
#ifndef uniBTree_H
#define uniBTree_H
#include "uniTreeNode.h"
#include <cassert>
template<class T>
class uniBTree {
private:
uniTreeNode<T> *root;
int delete_helper(uniTreeNode<T> *);
uniTreeNode<T> *insert_helper(uniTreeNode<T> *, const T);
void in_print_helper(const uniTreeNode<T> *) const;
void pre_print_helper(const uniTreeNode<T> *) const;
void post_print_helper(const uniTreeNode<T> *) const;
public:
uniBTree(void);
uniBTree(uniTreeNode<T> *r);
~uniBTree(void);
void insert(const T i);
void in_print(void) const;
void pre_print(void) const;
void post_print(void) const;
};
template<class T>
uniBTree<T>::uniBTree(void)
{
root = NULL;
}
template<class T>
uniBTree<T>::uniBTree(uniTreeNode<T> *r)
{
root = r;
}
template<class T>
int uniBTree<T>::delete_helper(uniTreeNode<T> *n)
{
int count = 0;
if (n == NULL)
return 0;
count += delete_helper(n->get_left());
count += delete_helper(n->get_right());
delete n;
count++;
return count;
}
template<class T>
uniBTree<T>::~uniBTree(void)
{
int count = delete_helper(root);
std::cout << "uniBTree<T>::~uniBTree<T>(void)\n";
std::cout << count << " nodes deleted\n";
}
template<class T>
void uniBTree<T>::in_print() const
{
in_print_helper(root);
}
template<class T>
void uniBTree<T>::pre_print() const
{
pre_print_helper(root);
}
template<class T>
void uniBTree<T>::post_print() const
{
post_print_helper(root);
}
template<class T>
void uniBTree<T>::in_print_helper(const uniTreeNode<T> *current) const
{
if (current == NULL)
return;
in_print_helper(current->get_left());
current->print();
in_print_helper(current->get_right());
}
template<class T>
void uniBTree<T>::pre_print_helper(const uniTreeNode<T> *current) const
{
if (current == NULL)
return;
current->print();
pre_print_helper(current->get_left());
pre_print_helper(current->get_right());
}
template<class T>
void uniBTree<T>::post_print_helper(const uniTreeNode<T> *current) const
{
if (current == NULL)
return;
post_print_helper(current->get_left());
post_print_helper(current->get_right());
current->print();
}
template<class T>
void uniBTree<T>::insert(const T i)
{
if (root == NULL)
root = new uniTreeNode<T>(i, NULL, NULL);
else
insert_helper(root, i);
}
template<class T>
uniTreeNode<T> *uniBTree<T>::insert_helper(uniTreeNode<T> *current, const T i)
{
if (current == NULL) {//this is will only dealed by attempting to visit leaves...
//if root is null, it'll be handled in insert
uniTreeNode<T> *child = new uniTreeNode<T>(i, NULL, NULL);
assert(child != NULL);
return(child);
}
if (i < current->get_data())
current->set_left(insert_helper(current->get_left(), i));
else
current->set_right(insert_helper(current->get_right(), i));
return(current);
}
#endif
uniTreeNode.h
#ifndef uniTreeNode_H//for redefinition
#define uniTreeNode_H
#include <iostream>
//using namespace std; don't use using namespace xxx and include source file in .h file
template<typename T>
class uniTreeNode {
private:
T data;
uniTreeNode<T> *left;
uniTreeNode<T> *right;
public:
//uniTreeNode<T>(void);
uniTreeNode(T d, uniTreeNode<T> *l, uniTreeNode<T> *r);
T get_data(void) const;
uniTreeNode<T> *get_left(void) const;
uniTreeNode<T> *get_right(void) const;
void set_left(uniTreeNode<T> *l);
void set_right(uniTreeNode<T> *r);
void print() const;
};
template<typename T>
uniTreeNode<T>::uniTreeNode/*remember syntax here*/
(T d , uniTreeNode<T> *l = NULL, uniTreeNode<T> *r = NULL)
{
data = d;
left = l;
right = r;
}
template<typename T>
T uniTreeNode<T>::get_data(void) const
{
return data;
}
template<typename T>
uniTreeNode<T> * uniTreeNode<T>::get_left(void) const
{
return left;
}
template<typename T>
uniTreeNode<T> * uniTreeNode<T>::get_right(void) const
{
return right;
}
template<typename T>
void uniTreeNode<T>::set_left(uniTreeNode<T> *l)
{
left = l;
}
template<typename T>
void uniTreeNode<T>::set_right(uniTreeNode<T> *r)
{
right = r;
}
template<typename T>
void uniTreeNode<T>::print() const
{
std::cout << "data is " << data << std::endl;
}
#endif
date.h
#include <ostream>
class date{
private:
int y;
int m;
int d;
public:
date();//default constructor
date(const long int);//used by cplr as convert constructor
date(int, int , int);
friend bool operator<(const date &d1, const date &d2);//d1 is for left-hand date
friend bool operator>(const date &d1, const date &d2);
bool operator==(date d);
bool operator!=(date d);
date &operator=(date d);
friend std::ostream &operator<<(std::ostream &out, date d);
friend std::istream &operator>>(std::istream &in, date d);
};
date.cc
#include <iostream>
#include <cstdio>
#include <time.h>
#include <cstring>
#include "date.h"
date::date(){
y = m = d = 0;
}
date::date(int Y, int M, int D){
y = Y;
m = M;
d = D;
}
date::date(const long int s){//#second since 1970/1/1 00:00:00
struct tm *buf;
buf = gmtime(&s);
y = (buf->tm_year+1900);
m = buf->tm_mon+1;
d = buf->tm_mday;
}
bool operator<(const date &d1, const date &d2){
bool result;//sizeof(bool) is 1
if(d1.y < d2.y) result = true;
else if(d1.y == d2.y){
if(d1.m < d2.m) result = true;
else if(d1.m == d2.m){
if(d1.d < d2.d) result = true;
else result = false;
}
else result = false;
}
else result = false;
return result;
}
bool operator>(const date &d1, const date &d2){
bool result;//sizeof(bool) is 1
if(d1.y > d2.y) result = true;
else if(d1.y == d2.y){
if(d1.m > d2.m) result = true;
else if(d1.m == d2.m){
if(d1.d > d2.d) result = true;
else result = false;
}
else result = false;
}
else result = false;
return result;
}
bool date::operator==(date d){
return (this->y==d.y && this->m==d.m && this->d==d.d);
}
bool date::operator!=(date d){
return (this->y!=d.y || this->m!=d.m || this->d!=d.d);
}
date &date::operator=(date d){
this->y = d.y;
this->m = d.m;
this->d = d.d;
return *this;
}
std::ostream &operator<<(std::ostream &out, date d){
out << d.y << "/" << d.m << "/" << d.d << std::endl;
return out;
}
std::istream &operator>>(std::istream &in, date d){
in >> d.y >> d.m >> d.d ;
return in;
}
main function
#include "uniBTree.h"
#include "date.h"
#include <cstdio>
int main(){
date d1 = 100000000;//convert constructor
uniTreeNode<date> node(d1, NULL, NULL);
printf("%p %p\n", node.get_left(), node.get_right());
std::cout << node.get_data() << std::endl;
date d2 = 86401;
date d3 = 200000000;
uniBTree<date> btree(&node);
return 0;
}
I tested and found that its &node that is invalid. I think it is because it tries to "release" btree at the end of the program and when the root is encountered, because it points to node, it can't perform good thing.
I have two question:
if construct a node like what I did,(uniTreeNode<date> node(xxx, xxx, xxx);) was the object "NEW"ed by the program?
for the uniTreeNode<T> class template, I didn't write its destructor!! So, like what I say above, when node,which is pointed by root of btree, is to be released is there so-called "default destructor"? and is it called here ? And most importantly, is "DELETE" used by the program?
If one of the two question above is no, is it why the problem arise?
EDIT: now the problem is shown, but how can I adjust my code to fix this? any one any idea?
EDIT: just modify like this:
uniTreeNode<date> *nodeptr = new uniTreeNode<date>(d1, NULL, NULL);
p.s. if not indirectly using a pointer to refer to our root of the btree(thus using new), new isn't used, and delete shouldn't be used; by this choice, delete_helper of uniTreenode should use this:
if(n != root){
delete n;
count++;
}
but this does not solve the problem...
the ultimate question is:
"can we release object without using delete(because it isn't obtained from newing) in c++?"
REPLY:
My "release"/"allocated" is actually saying about the memory, without specifying HOW it is done...but it's a big issue anyway
You say "you can do that but it is almost always the wrong answer";you mean that I should use DELETE but not directly call the destructor?(actually that doesn't seem proper at all)
-->please justify here
Btw, for those instance NEWed by me, is it necessary for them to be DELETED by a statement if I want to release them? or they'll also be dealt like those automatic variable instance?(back when out of scope, by compiler)
-->please correct the above if needed
another Q: isn't there ANY existing statement I can use to do things, like what DELETE does, for those automatic instance? or, I can only call destructor, if I wish?
Answer to your questions:
No, it allocated memory on the stack at compilation time and just ran the constructor on that.
You can't delete a pointer not allocated using new. The compiler inserts a call to the destructor (default or not) for uniTreeNode when the object node is done in main().
So to surmise, you cannot use delete on a pointer that is not allocated using new.
Simplest fix would be to allocate node using new:
uniTreeNode<date>* node = new uniTreeNode<date>(d1);
uniBTree<date> btree(node);
Learn to use valgrind.
It tells you right away what the problem is, you're deleting a stack object in the uniBTree destructor
==23648== Invalid free() / delete / delete[] / realloc()
==23648== at 0x4A0736C: operator delete(void*) (vg_replace_malloc.c:480)
==23648== by 0x400D78: uniBTree<date>::delete_helper(uniTreeNode<date>*) (uniBTree.h:48)
==23648== by 0x400CD5: uniBTree<date>::~uniBTree() (uniBTree.h:56)
==23648== by 0x400B91: main (main.cc:17)
==23648== Address 0x7fefffab0 is on thread 1's stack
==23648==
The destructor calls delete but &node was not created by new (you can tell that because you didn't write new!)
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 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) && ...
}
};
###MyClass.h###
#ifndef _MyClass
#define _MyClass
#include <string>
using namespace std;
class MyClass
{
public:
MyClass(const string name, const string text);
void display(ostream & out) const;
MyClass & operator = (const MyClass & m);
int compare(const MyClass & right) const;
private:
string _name;
string _text;
};
bool operator < (const MyClass & left, const MyClass & right);
ostream & operator << (ostream & out, const MyClass & mc);
#endif
###Node.h###
#include <string>
#include "MyClass.h"
using namespace std;
typedef MyClass * DataType;
class Node
{
private:
DataType item; // data
Node * lchild; // left child pointer
Node * rchild; // right child pointer
public:
Node(DataType Item);
DataType getItem() const;
void setItem(const DataType & data);
Node* getLChild() const;
void setLChild(Node * p);
Node* getRChild() const;
void setRChild(Node * p);
virtual ~Node();
};
###BST.h###
#include "Node.h"
using namespace std;
class BST
{
private:
Node * root;
bool Search(const DataType item, Node * r) const;
void Insert (DataType item, Node * ptr);
void Destructor(const Node * r);
public:
BST();
bool IsEmpty() const;
void Insert(const DataType item);
bool Search(const DataType item) const;
virtual ~BST();
};
###MyClass.cpp###
#include <iostream>
#include "MyClass.h"
using namespace std;
MyClass::MyClass(const string name, const string text)
{
_name = name;
_text = text;
}
void MyClass::display(ostream & out) const
{
out << "Name: " << _name << endl;
out << "Text: " << _text << endl;
}
MyClass & MyClass::operator = (const MyClass & m)
{
if (this == & m)
return *this;
_name = m._name;
_text = m._text;
return *this;
}
int MyClass::compare(const MyClass & right) const
{
return _name.compare(right._name);
}
bool operator < (const MyClass & left, const MyClass & right)
{
return left.compare(right) > 0;
}
ostream & operator << (ostream & out, const MyClass & mc)
{
mc.display(out);
return out;
}
###Node.cpp###
#include "Node.h"
Node::Node(DataType Item):item(Item)
{
lchild = 0;
rchild = 0;
}
DataType Node::getItem() const
{
DataType anItem = item;
return anItem;
}
void Node::setItem( const DataType & data)
{
item = data;
}
Node* Node::getLChild() const
{
Node * p = lchild;
return p;
}
void Node::setLChild(Node * p)
{
lchild = p;
}
Node* Node::getRChild() const
{
Node * p = rchild;
return p;
}
void Node::setRChild(Node * p)
{
rchild = p;
}
Node::~Node()
{
}
###BST.cpp###
#include <iostream>
#include "BST.h"
using namespace std;
bool BST::Search(const DataType item) const
{
return Search(item, root);
}
bool BST::Search(const DataType item, Node * r) const
{
if(r != 0)
{
if (item == r->getItem())
return true;
else
{
if (item < r->getItem())
return Search(item, r->getLChild());
else
return Search(item, r->getRChild());
}
}
else
return false;
}
BST::BST()
{
root = 0;
}
bool BST::IsEmpty() const
{
return (root == 0);
}
void BST::Insert(const DataType item)
{
if(root == 0)
root = new Node(item);
else
Insert(item, root);
}
void BST::Insert(DataType item, Node * ptr)
{
if (item < ptr->getItem())
{
if (ptr->getLChild() == 0)
ptr->setLChild(new Node(item));
else
Insert(item, ptr->getLChild());
}
else
{
if (ptr->getRChild() == 0)
ptr->setRChild(new Node(item));
else
Insert(item, ptr->getRChild());
}
}
void BST::Destructor(const Node * r)
{
if(r!=0)
{
Destructor( r->getLChild());
Destructor( r->getRChild());
delete r;
}
}
BST::~BST()
{
Destructor(root);
}
###main.cpp###
#include <iostream>
#include "MyClass.h"
#include "BST.h"
using namespace std;
void main()
{
MyClass * mc1 = new MyClass("Tree","This is a tree");
MyClass * mc2 = new MyClass("Book","This is a book");
MyClass * mc3 = new MyClass("Zoo","This is a zoo");
BST * tree = new BST();
tree->Insert(mc1);
tree->Insert(mc2);
tree->Insert(mc3);
cout << boolalpha << ("Book" < "Tree") << endl;
cout << (mc2 < mc1) << endl;
cout << (tree->Search(new MyClass("Book",""))) << endl;
}
Result is true false false
I don't know what's wrong with my operator overloading? (mc2 should
less than mc1)
I'm not sure if this is correct for searching a "MyClass" node in a BST?
and the result is "not found"....I traced it into "BST.cpp",
and found that the problem also occurs at " if (item < r->getItem()) "
Can anyone help me or give me a hint....thank you so much!
Here you are just comparing pointers, i.e memory addresses:
cout << (mc2 < mc1) << endl;
To compare the objects, you need to dereference the pointers:
cout << ((*mc2) < (*mc1)) << endl;
In your code snippet, there is no reason for mc1, mc2, etc. to be pointers, so you could avoid the problem by creating objects on the stack directly:
MyClass mc1("Tree","This is a tree");
and so on. I would even go further and say that you should only dynamically allocate objects with new if you really are sure you need to and have good reasons not to allocate automatically on the stack. And if you really must use dynamically allocated pointers, have a look at C++ smart pointers.