I'm trying to build a custom dictionary class with custom string and definition classes. While trying to overload the >> (input) I get some kind of a problem. when the function ends the dictionary sent to it doesn't change. attaching the code:
This is the overloading:
istream& operator>>(istream& ip, Dictionary& var) {
Definition temp;
ip >> temp;
var += temp;
return ip;
}
and some other functions used in it:
Dictionary& Dictionary::operator+=(Definition& input) {
if (!checkCopy(input))
{
Definition** temp;
temp = new Definition*[numWords + 1];
for (int i = 0; i < numWords; i++)
{
temp[i] = book[i];
}
numWords++;
temp[numWords - 1] = &input;
delete[] book;
book = temp;
}
return *this;
}
Dictionary::Dictionary(Dictionary& input) {
*this = input;
}
Dictionary& Dictionary::operator=(Dictionary& input) {
if (numWords != 0)
delete[] book;
book = new Definition*[input.numWords];
for (int i = 0; i < input.numWords; i++)
{
*this += *input.book[i];
}
return *this;
}
And the class itself:
class Dictionary
{
private:
int numWords = 0;
Definition** book;
public:
Dictionary();
~Dictionary();
Dictionary(Dictionary&);
bool operator==(Dictionary&) const;
Dictionary& operator=(Definition&);
Dictionary& operator=(Dictionary&);
friend ostream& operator<<(ostream&, const Dictionary&);
friend istream& operator>>(istream&, Dictionary&);
Dictionary& operator-=(int);
Dictionary& operator+=(Definition&);
bool checkCopy(Definition&);
Definition& operator[](int); //left side brackets for input
Definition operator[](int) const; //right side brackets for output
};
EDIT: here is also the overloading operator for definition input:
istream& operator>>(istream& ip, Definition& var)
{
cout << "Please enter a word: " << endl;
ip >> var.word;
cout << "Please enter the number of definitions for this word: " << endl;
int idx;
cin >> idx;
while (idx<0)
{
cout << "Error: number of definitions not possible. Please Try again: " << endl;
cin.clear();
cin.ignore(INT_MAX, '\n');
cin >> idx;
}
cin.clear();
cin.ignore(INT_MAX, '\n');
String* temp = new String[idx];
for (int i = 0; i < idx; i++) {
cout << "Please enter the " << i + 1 << "th definition: " << endl;
cin >> temp[i];
var += temp[i];
}
var.sortDefinition();
return ip;
}
Help is indeed needed.
You should really stick to std::vector and other collection types rather than juggling around with pointers and new/delete as you do here.
In your operator+= function you're copying the address of a temporary variable into your array:
temp[numWords - 1] = &input;
Once the calling function operator>> ends, this pointer is less than worthless, because the original object (Definition temp;) does not exist any longer. Therefore the behaviour of that code is undefined!
You might get around this by defining a copy c'tor for Definition and then changing above line to:
*temp[numWords - 1] = input;
Also in your assignment operator you're making use of the operator+= function. However, your numWords member is not set appropriately at this time, so operator+= will likely do the wrong thing. So add a line to the assignment operator like this:
if (numWords != 0)
{
delete[] book;
numWords = 0; // add this line
}
There were 2 problems:
what Alexander said about the temporary variable. changed it to:
Dictionary& Dictionary::operator+=(Definition& input) {
if (!checkCopy(input))
{
Definition** temp;
temp = new Definition*[numWords + 1];
temp[0] = new Definition[numWords];
for (int i = 0; i < numWords; i++)
{
temp[i] = book[i];
}
temp[0][numWords] = input;
delete[] book;
book = temp;
numWords++;
}
return *this;
}
The second was that in the Definition class when I tried to access the number of definitions in an object that wasn't created due to the double pointer:
Definition** temp;
temp = new Definition*[numWords + 1];
So I changed it so it won't access it but first build it.
Thanks for the help Alexander!
Related
I use a for loop and if-else statement to try to sort the titles of the books alphabetically. However, I am facing some errors under the returnlistofBooks method. Is there any ways to fix this problem?
voidBookshelf::voidBookshelf(vector <Book*> listofBooks){
this->listofBooks = listofBooks;
}
void voidBookshelf::addBook()
{
int ID;
string Title;
string Author;
for (int i = 1; i <= 5; i++)
{
cout << "Book#"<< i << ":" << endl;
cout << "Enter an ID:";
cin >> ID;
cout << "Enter a title:";
cin >> Title;
cout << "Enter an author:";
cin >> Author;
Book *mybook = new Book(ID, Title, Author); //book object
listofBooks.push_back(mybook);
}
}
void returnListofBooks(int count, string name)
{
Book temp;
for (int i = 0; i < count; i++)
{
for (int j = 0; j < count - i; j++)
{
if (books[j].author > books[j + 1].author)
{
//swapping the instances themselves, but still comparing by the member.
temp = books[j];
books[j] = books[j + 1];
books[j + 1] = temp;
}
}
}
}
int main(){
voidBookshelf * myBookshelf = new voidBookshelf;
myBookshelf->addBook();
myBookshelf->returnListofBooks();
return 0;
}
you can check here for sort function!it is quite simple!
go to:
http://www.cplusplus.com/articles/NhA0RXSz/
An easy method to allow sorting is to overload operator< in your class:
class Book
{
public:
bool operator< (const Book& b)
{
return author < b.author;
}
private:
std::string author;
};
If you want to sort by other fields, you will need to write a custom comparison operator:
class Book
{
std::string title;
friend bool order_by_title(const Book& a, const Book& b);
};
bool order_by_title(const& Book a, const Book& b)
{
return a.title < b.title;
}
std::vector<Book> library;
//...
std::sort(library.begin(), library.end(), order_by_title);
well i have a bit problem understanding references in c++, especially while returning reference of a class from a method.
like the code below works perfectly:(the bold portion is where the problem lies)
#include<iostream>
using namespace std;
class Sequence
{
int *a;
int length;
void allocMemory()
{
this->a = new int[this->length];
}
void fill(int val)
{
for (int i = 0; i<this->length; i++) this->a[i] = val;
}
public:
Sequence(int len=0)
{
this->length=len;
this->allocMemory();
this->fill(0);
}
Sequence(int data,int len)
{
this->length=len;
this->allocMemory();
this->fill(data);
}
Sequence(int *data,int len)
{
this->length=len;
this->allocMemory();
for(int i=0;i<this->length;i++) this->a[i]=data[i];
}
Sequence(const Sequence &s)
{
length=s.length;
allocMemory();
for(int i=0;i<length;i++){
a[i]=s.a[i];
}
}
~Sequence()
{
delete [] this->a;
}
friend ostream & operator<<(ostream &stream, Sequence &s)
{
stream << "Sequence: " ;
for(int i=0;i<s.length;i++) stream << s.a[i] << " ";
stream << " Length = " << s.length << endl;
return stream;
}
friend istream & operator>>(istream &stream, Sequence &s)
{
int n;
cout << "No of elements:";
stream >> n;
s.length=n;
s.allocMemory();
cout << "Enter the elements:";
for(int i=0;i<n;i++) stream >> s.a[i];
return stream;
}
Sequence &operator= (int data){ // this method works fine as i return a reference
for(int i=0;i<length;i++){
a[i]=data;
}
return *this;
}
**Sequence operator+(Sequence ob){
/*this is the problematic method. It works fine this way. as i already got
the necessary copy constructor code. But if i change the return value to a
reference like the sample code within the comment, the program doesn't give the correct output. Though as per my theoretical knowledge, i can't find any problem in this code which too should run perfectly even if the copy constructor code was missing.
Sequence & operator+(Sequence ob){
int i,j;
int l=length+ob.length;
Sequence temp(0,l);
for(i=0;i<length;i++){
temp.a[i]=a[i];
}
for(j=0;i<l || j<ob.length;i++,j++){
temp.a[i]=ob.a[j];
}
return temp;
}
*/**
int i,j;
int l=length+ob.length;
Sequence temp(0,l);
for(i=0;i<length;i++){
temp.a[i]=a[i];
}
for(j=0;i<l || j<ob.length;i++,j++){
temp.a[i]=ob.a[j];
}
return temp;
}
void show(){
for(int i=0;i<length;i++){
cout<<a[i]<<" ";
}
}
};
int main(){
int arr[]={1,2,3,4,5,6,7,8,9,10};
Sequence a(arr,10);
cout << a;
Sequence b(10);
cout << b;
cin >> b;
cout << b;
Sequence c=a+b;
c.show();
}
You can't return a temporary by reference - you'd be left with a dangling reference outside the function because the object is destroyed when the function ends.
Idiomatically, operator+ returns by value. In comparison, operator+= returns by reference (to enable chaining), but you'd return *this, which isn't temporary and makes it valid.
for a class project I have a 2D array of pointers. I understand the constructors, destructors, etc. but I'm having issues understanding how to set the values in the array. We're using the overloaded input operator to input the values.
Here is the code I have for that operator so far:
istream& operator>>(istream& input, Matrix& matrix)
{
bool inputCheck = false;
int cols;
while(inputCheck == false)
{
cout << "Input Matrix: Enter # rows and # columns:" << endl;
input >> matrix.mRows >> cols;
matrix.mCols = cols/2;
//checking for invalid input
if(matrix.mRows <= 0 || cols <= 0)
{
cout << "Input was invalid. Try using integers." << endl;
inputCheck = false;
}
else
{
inputCheck = true;
}
input.clear();
input.ignore(80, '\n');
}
if(inputCheck = true)
{
cout << "Input the matrix:" << endl;
for(int i=0;i< matrix.mRows;i++)
{
Complex newComplex;
input >> newComplex;
matrix.complexArray[i] = newComplex; //this line
}
}
return input;
}
Obviously the assignment statement I have here is incorrect, but I'm not sure how it is supposed to work. If it's necessary that I include more code, let me know.
This is what the main constructor looks like:
Matrix::Matrix(int r, int c)
{
if(r>0 && c>0)
{
mRows = r;
mCols = c;
}
else
{
mRows = 0;
mCols = 0;
}
if(mRows < MAX_ROWS && mCols < MAX_COLUMNS)
{
complexArray= new compArrayPtr[mRows];
for(int i=0;i<mRows;i++)
{
complexArray[i] = new Complex[mCols];
}
}
}
and here is Matrix.h so you can see the attributes:
class Matrix
{
friend istream& operator>>(istream&, Matrix&);
friend ostream& operator<<(ostream&, const Matrix&);
private:
int mRows;
int mCols;
static const int MAX_ROWS = 10;
static const int MAX_COLUMNS = 15;
//type is a pointer to an int type
typedef Complex* compArrayPtr;
//an array of pointers to int type
compArrayPtr *complexArray;
public:
Matrix(int=0,int=0);
Matrix(Complex&);
~Matrix();
Matrix(Matrix&);
};
#endif
the error I'm getting is "cannot convert Complex to Matrix::compArrayPtr (aka Complex*) in assignment" If anyone can explain what I'm doing wrong, I'd be very grateful.
Your newComplex is an object of type Complex (a value) and you try to assign it to a Complex* pointer.
For this to work you should construct a complex dynamically:
Complex* newComplex = new Complex();
input >> *newComplex;
matrix.complexArray[i] = newComplex;
But be aware of all the consequences that come with dynamic allocation (memory management, ownership, shared state...).
This is my first time with much of this code. With this instancepool.h file below I get errors saying I can't use vector (line 14) or have instance& as a return type (line 20). It seems it can't use the instance objects despite the fact that I have included them.
#ifndef _INSTANCEPOOL_H
#define _INSTANCEPOOL_H
#include "instance.h"
#include <iostream>
#include <string>
#include <vector>
#include <stdlib.h>
using namespace std;
class InstancePool
{
private:
unsigned instances;//total number of instance objects
vector<instance> ipp;//the collection of instance objects, held in a vector
public:
InstancePool();//Default constructor. Creates an InstancePool object that contains no Instance objects
InstancePool(const InstancePool& original);//Copy constructor. After copying, changes to original should not affect the copy that was created.
~InstancePool();//Destructor
unsigned getNumberOfInstances() const;//Returns the number of Instance objects the the InstancePool contains.
const instance& operator[](unsigned index) const;
InstancePool& operator=(const InstancePool& right);//Overloading the assignment operator for InstancePool.
friend istream& operator>>(istream& in, InstancePool& ip);//Overloading of the >> operator.
friend ostream& operator<<(ostream& out, const InstancePool& ip);//Overloading of the << operator.
};
#endif
Here is the instance.h :
#ifndef _INSTANCE_H
#define _INSTANCE_H
///////////////////////////////#include "instancepool.h"
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
class Instance
{
private:
string filenamee;
bool categoryy;
unsigned featuress;
unsigned* featureIDD;
unsigned* frequencyy;
string* featuree;
public:
Instance (unsigned features = 0);//default constructor
unsigned getNumberOfFeatures() const; //Returns the number of the keywords that the calling Instance object can store.
Instance(const Instance& original);//Copy constructor. After copying, changes to the original should not affect the copy that was created.
~Instance() { delete []featureIDD; delete []frequencyy; delete []featuree;}//Destructor.
void setCategory(bool category){categoryy = category;}//Sets the category of the message. Spam messages are represented with true and and legit messages with false.//easy
bool getCategory() const;//Returns the category of the message.
void setFileName(const string& filename){filenamee = filename;}//Stores the name of the file (i.e. “spam/spamsga1.txt”, like in 1st assignment) in which the message was initially stored.//const string& trick?
string getFileName() const;//Returns the name of the file in which the message was initially stored.
void setFeature(unsigned i, const string& feature, unsigned featureID,unsigned frequency) {//i for array positions
featuree[i] = feature;
featureIDD[i] = featureID;
frequencyy[i] = frequency;
}
string getFeature(unsigned i) const;//Returns the keyword which is located in the ith position.//const string
unsigned getFeatureID(unsigned i) const;//Returns the code of the keyword which is located in the ith position.
unsigned getFrequency(unsigned i) const;//Returns the frequency
Instance& operator=(const Instance& right);//Overloading of the assignment operator for Instance.
friend ostream& operator<<(ostream& out, const Instance& inst);//Overloading of the << operator for Instance.
friend istream& operator>>(istream& in, Instance& inst);//Overloading of the >> operator for Instance.
};
#endif
Also, if it is helpful here is instance.cpp:
// Here we implement the functions of the class apart from the inline ones
#include "instance.h"
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
Instance::Instance(unsigned features) { //Constructor that can be used as the default constructor.
featuress = features;
if (features == 0)
return;
featuree = new string[featuress]; // Dynamic memory allocation.
featureIDD = new unsigned[featuress];
frequencyy = new unsigned[featuress];
return;
}
unsigned Instance::getNumberOfFeatures() const {//Returns the number of the keywords that the calling Instance object can store.
return featuress;}
Instance::Instance(const Instance& original) {//Copy constructor.
filenamee = original.filenamee;
categoryy = original.categoryy;
featuress = original.featuress;
featuree = new string[featuress];
for(unsigned i = 0; i < featuress; i++) {
featuree[i] = original.featuree[i];
}
featureIDD = new unsigned[featuress];
for(unsigned i = 0; i < featuress; i++) {
featureIDD[i] = original.featureIDD[i];
}
frequencyy = new unsigned[featuress];
for(unsigned i = 0; i < featuress; i++) {
frequencyy[i] = original.frequencyy[i];}
}
bool Instance::getCategory() const { //Returns the category of the message.
return categoryy;}
string Instance::getFileName() const { //Returns the name of the file in which the message was initially stored.
return filenamee;}
string Instance::getFeature(unsigned i) const { //Returns the keyword which is located in the ith position.//const string
return featuree[i];}
unsigned Instance::getFeatureID(unsigned i) const { //Returns the code of the keyword which is located in the ith position.
return featureIDD[i];}
unsigned Instance::getFrequency(unsigned i) const { //Returns the frequency
return frequencyy[i];}
Instance& Instance::operator=(const Instance& right) { //Overloading of the assignment operator for Instance.
if(this == &right) return *this;
delete []featureIDD;
delete []frequencyy;
delete []featuree;
filenamee = right.filenamee;
categoryy = right.categoryy;
featuress = right.featuress;
featureIDD = new unsigned[featuress];
frequencyy = new unsigned[featuress];
featuree = new string[featuress];
for(unsigned i = 0; i < featuress; i++) {
featureIDD[i] = right.featureIDD[i]; }
for(unsigned i = 0; i < featuress; i++) {
frequencyy[i] = right.frequencyy[i]; }
for(unsigned i = 0; i < featuress; i++) {
featuree[i] = right.featuree[i]; }
return *this;
}
ostream& operator<<(ostream& out, const Instance& inst) {//Overloading of the << operator for Instance.
out << endl << "<message file=" << '"' << inst.filenamee << '"' << " category=";
if (inst.categoryy == 0)
out << '"' << "legit" << '"';
else
out << '"' << "spam" << '"';
out << " features=" << '"' << inst.featuress << '"' << ">" <<endl;
for (int i = 0; i < inst.featuress; i++) {
out << "<feature id=" << '"' << inst.featureIDD[i] << '"' << " freq=" << '"' << inst.frequencyy[i] << '"' << "> " << inst.featuree[i] << " </feature>"<< endl;
}
out << "</message>" << endl;
return out;
}
istream& operator>>(istream& in, Instance& inst) { //Overloading of the >> operator for Instance.
string word;
string numbers = "";
string filenamee2 = "";
bool categoryy2 = 0;
unsigned featuress2;
string featuree2;
unsigned featureIDD2;
unsigned frequencyy2;
unsigned i;
unsigned y;
while(in >> word) {
if (word == "<message") {//if at beginning of message
in >> word;//grab filename word
for (y=6; word[y]!='"'; y++) {//pull out filename from between quotes
filenamee2 += word[y];}
in >> word;//grab category word
if (word[10] == 's')
categoryy2 = 1;
in >> word;//grab features word
for (y=10; word[y]!='"'; y++) {
numbers += word[y];}
featuress2 = atoi(numbers.c_str());//convert string of numbers to integer
Instance tempp2(featuress2);//make a temporary Instance object to hold values read in
tempp2.setFileName(filenamee2);//set temp object to filename read in
tempp2.setCategory(categoryy2);
for (i=0; i<featuress2; i++) {//loop reading in feature reports for message
in >> word >> word >> word;//skip two words
numbers = "";//reset numbers string
for (int y=4; word[y]!='"'; y++) {//grab feature ID
numbers += word[y];}
featureIDD2 = atoi(numbers.c_str());
in >> word;//
numbers = "";
for (int y=6; word[y]!='"'; y++) {//grab frequency
numbers += word[y];}
frequencyy2 = atoi(numbers.c_str());
in >> word;//grab actual feature string
featuree2 = word;
tempp2.setFeature(i, featuree2, featureIDD2, frequencyy2);
}//all done reading in and setting features
in >> word;//read in last part of message : </message>
inst = tempp2;//set inst (reference) to tempp2 (tempp2 will be destroyed at end of function call)
return in;
}
}
}
and instancepool.cpp:
// Here we implement the functions of the class apart from the inline ones
#include "instancepool.h"
#include "instance.h"
#include <iostream>
#include <string>
#include <vector>
#include <stdlib.h>
using namespace std;
InstancePool::InstancePool()//Default constructor. Creates an InstancePool object that contains no Instance objects
{
instances = 0;
ipp.clear();
}
InstancePool::~InstancePool() {
ipp.clear();}
InstancePool::InstancePool(const InstancePool& original) {//Copy constructor.
instances = original.instances;
for (int i = 0; i<instances; i++) {
ipp.push_back(original.ipp[i]);
}
}
unsigned InstancePool::getNumberOfInstances() const {//Returns the number of Instance objects the the InstancePool contains.
return instances;}
const Instance& InstancePool::operator[](unsigned index) const {//Overloading of the [] operator for InstancePool.
return ipp[index];}
InstancePool& InstancePool::operator=(const InstancePool& right) {//Overloading the assignment operator for InstancePool.
if(this == &right) return *this;
ipp.clear();
instances = right.instances;
for(unsigned i = 0; i < instances; i++) {
ipp.push_back(right.ipp[i]); }
return *this;
}
istream& operator>>(istream& in, InstancePool& ip) {//Overloading of the >> operator.
ip.ipp.clear();
string word;
string numbers;
int total;//int to hold total number of messages in collection
while(in >> word) {
if (word == "<messagecollection"){
in >> word;//reads in total number of all messages
for (int y=10; word[y]!='"'; y++){
numbers = "";
numbers += word[y];
}
total = atoi(numbers.c_str());
for (int x = 0; x<total; x++) {//do loop for each message in collection
in >> ip.ipp[x];//use instance friend function and [] operator to fill in values and create Instance objects and read them intot he vector
}
}
}
}
ostream& operator<<(ostream& out, const InstancePool& ip) {//Overloading of the << operator.
out << "<messagecollection messages=" << '"' << '>' << ip.instances << '"'<< endl << endl;
for (int z=0; z<ip.instances; z++) {
out << ip[z];}
out << endl<<"</messagecollection>\n";
}
This code is currently not writing to files correctly either at least, I'm sure it has many problems. I hope my posting of so much is not too much, and any help would be very much appreciated. Thanks!
You created an Instance type but are trying to use instance. Case matters.
class string
{
public:
friend istream& operator >> ( istream& is, string& str);
private:
char *m_data;
};
int main()
{
string str;
freopen("in.txt","r",stdin);
while( cin >> str)
{
cout < < str < < endl;
}
return 0;
}
the content of in.txt are:
asdfsfgfdgdfg
in the overload function, i use is.get() to read those charaters one by one,but program jump out the circle when cin finish,that means cout will not run. on the other way,i try getchar() instead, but it can not jump out the circle.
question: is there any wrong in my idea towards this function? or there is another better way to fulfill. thx :)
=========================================================================================
new edit:
here my code:
#Artem Barger
code detail
#include <iostream>
namespace Str
{
class string
{
public:
string():k(0){}
friend bool operator >> ( std::istream& is, string& str)
{
int size = 100;
char m;
if( (m = getchar()) && m == -1)
return false;
str.m_data = new char[size];
do
{
if( str.k == size)
{
size *= 2;
char *temp = new char[size];
for( int j = 0; j < str.k; ++j)
{
char *del = str.m_data;
temp[j] = *str.m_data++;
delete del;
}
str.m_data = temp;
temp = NULL;
}
str.m_data[str.k++] = m;
}while( (m = getchar()) && m != -1);
return true;
}
friend void operator << ( std::ostream& os, string& str)
{
os << str.m_data;
str.k = 0;
delete []str.m_data;
}
private:
char *m_data;
int k;
};
}
using namespace Str;
int main()
{
string str;
while( std::cin >> str)
{
std::cout << str;
}
return 0;
}
still have some problem in the content of
do
{
}while();
Perhaps you could rewrite your code like this, which should fix your problem:
bool success = true;
while (sucess) {
success = cin >> str;
cout << str;
}
However, I don't understand why you still want the cout to go ahead - if the cin call didn't succeed, you will only be printing the old contents of the string - you do not clear it anywhere (unless you do so in other code which you haven't posted here).