returning reference of a class - c++

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.

Related

Trouble with operator << in class StringSet

I am defining my own string class called StringSet using a vector of strings. I am assigned to overload the >>, <<, ==, >, >=, +, += and * operators, and ran into a problem with <<. The output should be:
Welcome to stringset
hi everyone
"all" does not exist in the set.
hi
But it seems to be skipping the second and third lines. I am very new to overloading operators, so I am probably overlooking an obvious mistake.
header and class declaration:
#include <iostream>
#include <vector>
#include<string>
#include <iterator>
#include <algorithm>
#include <fstream>
using namespace std;
class StringSet
{
public:
//Constructor
StringSet();
//Copy Constructor
StringSet(const StringSet& s);
//Default constructors
StringSet(string initialStrings[], const int ARRAYSIZE);
//Destructor
~StringSet();
void add(const string s);
void remove(const string s);
//Returns length
int size()
{
return length;
}
// Overload the << operator so that it outputs the strings
friend ostream& operator <<(ostream& outs, const StringSet& s);
private:
//size of the vector
int length;
// Vector to store strings
vector <string> data;
};
function definitions:
ostream& operator<<(ostream& outs, const StringSet& s)
{
outs << "\n";
for (int i = 0; i < s.length; i++)
{
outs << s.data[i] << " ";
}
outs << "\n";
return outs;
}
//Add a string to the vector
void StringSet::add(const string s)
{
bool c = check(s);
if (c == false)
{
data.push_back(s);
}
else
{
cout << "\"" << s << "\" already exists in the set.";
}
}
// Remove a string from the vector
void StringSet::remove(const string s)
{
bool c = check(s);
if (c == true)
{
vector<string>::iterator position = search(s);
data.erase(position);
}
else
{
cout << "\"" << s << "\" does not exist in the set\n";
}
}
StringSet::StringSet()
{
length = 0;
}
StringSet::StringSet(string initialStrings[], const int ARRAYSIZE)
{
for (int i = 0; i < data.size(); i++)
{
initialStrings[i] = " ";
}
}
// Copy constructor
StringSet::StringSet(const StringSet& s)
{
for (int i = 0; i < data.size(); i++)
{
data[i] = s.data[i];
}
}
StringSet::StringSet()
{
length = 0;
}
StringSet::StringSet(string initialStrings[], const int ARRAYSIZE)
{
for (int i = 0; i < data.size(); i++)
{
initialStrings[i] = " ";
}
}
// Copy constructor
StringSet::StringSet(const StringSet& s)
{
for (int i = 0; i < data.size(); i++)
{
data[i] = s.data[i];
}
}
// Check if a string exists in the vector
bool StringSet::check(const string s)
{
vector<string>::iterator it = find(data.begin(), data.end(), s);
if (it != data.end())
{
return true;
}
else
{
return false;
}
}
Main function:
int main()
{
ofstream outs;
ifstream ins;
StringSet doc1, doc2, query
cout << "Welcome to stringset\n";
doc1.add("hi");
doc1.add("everyone");
outs << doc1;
doc1.remove("everyone");
doc1.remove("all");
outs << doc1;
}
If you use a variable that stores the size of the set, you should increment/decrement it when adding/removing elements. You can also change the definition of the StringSet::size():
int size() const
{
return static_cast<int>(data.size());
}

Operator overloading in C++ of a matrix template

I'm trying to implement a Matrix template. I've overloaded the <<, >> and + operators. << and >> are working properly but + is not working as expected. After using the + operator I am getting some random output in the last line. Can anyone tell me what is wrong?
#include<iostream>
using namespace std;
template <class V>
class mat
{
public:
int row,col;
V **a;
mat(int r,int c)
{
row=r;
col=c;
a=new V*[r];
for(int i=0;i<row;i++)
{
a[i]=new V[col];
}
}
mat(const mat &x) //Copy constructor
{
row=x.row;
col=x.col;
a=new V*[row];
for(int i=0;i<row;i++)
{
a[i]=new V[col];
}
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
a[i][j]=x.a[i][j];
}
}
}
~mat()
{
//cout << "Deleting Matrix\n" << endl;
for(int i=0;i<row;i++)
{
delete []a[i];
}
}
friend ostream &operator<<(ostream &p,const mat &z)
{
for(int i=0;i<z.row;i++)
{
for(int j=0;j<z.col;j++)
{
p << z.a[i][j] <<" ";
}
cout << endl;
}
return p;
}
friend istream &operator>>(istream &p,mat &z)
{
for(int i=0;i<z.row;i++)
{
for(int j=0;j<z.col;j++)
{
p >> z.a[i][j];
}
}
return p;
}
mat<V> operator+(mat<V> z)
{
mat<V> b(row,col);
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
b.a[i][j]=a[i][j]+z.a[i][j];
}
}
return b;
}
};
int main()
{
mat<int> p(2,2),q(2,2),z(2,2);
cin>>p>>q;
cout<<p<<q<<endl; //working properly
z=p+q;
cout<<z<<endl; // getting wrong output here
return 0;
}
In C++, I recommand to use operator +=, -=, *=, /= and others like them be internal to the class. The operators +, *, -, / should be external.
So you could do something like this:
class A {
A &operator +=(A const &b) {
... code
return *this;
}
};
A operator+(A a1, A const &a2) {
return a1 += a2;
}
thanks to vsoftco for the tip
To answer more precisely to your question, you just did not define the operator=
If you do mat z = p + q; it will works ;).
See my comments below for further details ;)
Inside of your operator+ you effectively have b = (*this) + z. You only however, check row and col from this. If z is smaller in either dimension you are going to be out of bounds.
You can check for this condition and figure out what to return if that happens (or throw an exception, the choice is yours):
mat<V> operator+(const mat<V>& z) const {
mat<V> b(row,col);
if (z.row != row || z.col != col) { return b; }
// ...
}
Or you can have the mat class be templated on the dimensions as well, which would make two different size matrices be different types
template <typename T, int Row, int Col>
class mat {
private:
T a[Row][Col];
// ...
};
The internals of your functions are working fine. But as others have mentioned above, there is something wrong with your function signatures, that is causing them to be called in a rather strange way.
I have added some debug output to your code to illustrate what is happening. You should add these changes, compile and run.
#include<iostream>
using namespace std;
template <class V>
class mat
{
public:
int row,col;
V **a;
mat(int r,int c)
{
row=r;
col=c;
a=new V*[r];
for(int i=0;i<row;i++)
{
a[i]=new V[col];
for (int cc=0; cc<col;++cc)
{
a[i][cc] = -77;
}
}
}
mat(const mat &x) //Copy constructor
{
cout << "copy to this: " << this << endl;
cout << "x: " << &x << endl;
row=x.row;
col=x.col;
a=new V*[row];
for(int i=0;i<row;i++)
{
a[i]=new V[col];
}
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
a[i][j]=x.a[i][j];
}
}
}
~mat()
{
//cout << "Deleting Matrix\n" << endl;
for(int i=0;i<row;i++)
{
delete []a[i];
}
}
friend ostream &operator<<(ostream &p,const mat &z)
{
for(int i=0;i<z.row;i++)
{
for(int j=0;j<z.col;j++)
{
p << z.a[i][j] <<" ";
}
cout << endl;
}
return p;
}
friend istream &operator>>(istream &p,mat &z)
{
for(int i=0;i<z.row;i++)
{
for(int j=0;j<z.col;j++)
{
p >> z.a[i][j];
}
}
return p;
}
mat<V> operator+(mat<V> z)
{
cout << "plus to this: " << this << endl;
mat<V> b(row,col);
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
b.a[i][j]=a[i][j]+z.a[i][j];
}
}
return b;
}
};
int main()
{
mat<int> p(2,2),q(2,2),z(2,2);
cin>>p>>q;
cout<<p<<q<<endl; //working properly
cout << "Before" << endl;
cout << "p : " << &p << endl;
cout << "q : " << &q << endl;
cout << "z : " << &z << endl;
cout << "After" << endl;
z=p+q;
cout<<q<<endl;
cout<<z<<endl; // getting wrong output here
return 0;
}
When I run I see the following output.
Before
p : 0026F75C
q : 0026F748
z : 0026F734
After
copy to this: 0026F61C
x: 0026F748
plus to this: 0026F75C
copy to this: 0026F654
x: 0026F5E8
From this you can see that when the line
z=p+q;
is run, the copy constructor is called to copy q to an anonymous object, then the operator+ function is called on another anonymous object.
Finally, when exiting the operator+ function, the copy constructor is called again, copying the result of operator+ function to a third anonymous object. At no time is anything copied to z, nor is the operator+ function called on p or q.
This code also segfaults on exit. I think the problem lies with creating anonymous objects, which is using the default constructor created by the compiler, which does not set row, col or intialise a.

C++ Overloading operator >> (input) doesn't change original

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!

C++ GET Array Error

I am having a problem with pieces[] at Copy Constructor and Equal Oparator. i am trying to get pieces like code and month_year but it drops me an error saying 'class machine' has no member named 'get'
#include <iostream>
#include <string>
using namespace std;
class machine {
public:
void set_code(string my_code){
code=my_code;
}
void set_month_year(int my_month_year){
month_year=my_month_year;
}
void set_pieces(int *my_pieces){
for(int i=0;i<25;i++)
pieces[i]=my_pieces[i];
}
string get_code(void){
return code;
}
int get_month_year(void){
return month_year;
int get_pieces_i(int i){
return pieces[i];
}
//Default Constructor
machine(){
code.erase();
month_year=0;
for(int i=0;i<25;i++)
pieces[i]=0;
}
//Destructor
~machine(){}
void print_data(void){
cout << "Code= " << code << endl;
cout << "Month Year " << month_year << endl;
}
void print_pieces(void){
for(int i=0;i<25;i++)
cout << pieces[i] << endl;
}
machine(string my_code, int my_month_year,int *my_pieces){
code=my_code;
month_year=my_month_year;
for(int i=0;i<25;i++)
pieces[i]=my_pieces[i];
}
//Copy Constructor
machine (machine& a)
{
code=a.get_code();
month_year=a.get_month_year();
pieces=a.get.pieces_i();
}
//Equal Operator
void operator = (machine & a)
{
code=a.get_code();
month_year=a.get_month_year();
pieces=a.get_pieces_i();
}
// month & year
int get_month(void) {
return month_year/100;
}
int get_year(void) {
return month_year%100;
}
//return 0 & 1
int ckeck_code(void) {
int counter=0;
for (int i=0;i<25;i++) {
if (pieces [i] <10) {
counter=counter+1;
}
if (counter<5)
return 0;
else
return 1;
}
}
private:
string code;
int month_year;
int pieces[25];
};
int main(void){
return 0;
}
Both copy constructor and assignment operator (yes, it's called assignment operator, not equal operator) should have their parameter of type const machine& instead of machine&.
On the get_* functions, they should be declared as constant member functions. That is,
string get_code(void) const {
return code;
}
int get_month_year(void) const {
return month_year;
}
int get_pieces_i(int i) const {
return pieces[i];
}
Furthermore, the copy constructor and assignment operator should handle pieces like:
for (int i = 0; i < 25; ++i)
pieces[i] = a.get_pieces_i(i);
to match the getters' prototype.

c++ getting error trying to call a function that reads a file

I have a function Readf I'm trying to call to fill in an array inside each constructor, I tried only with the default constructor with a code statement ReadF(cap,*point,counter);.
The second argument is what's giving me a problem in figuring out, I would get an error with '&' beside it or ' '. And I get an external error with the '*', I'm still new to c++ so I'm not experienced in dealing with classes.
I have to use the ReadF member function, are there other ways instead of calling it to get the results I need.
Also some of the code for the functions I have might not be perfect, but I would like to deal with this problem first before I move on to another.
array.h:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
class AR {
public:
AR();
AR(int);
AR(const AR&);
//~AR();
void ReadF(const int, string&, int);
AR& operator=(const AR&);
friend ostream& operator<<(ostream&, AR&);
friend ifstream & operator>>(ifstream&, AR&);
private:
string* point;
int counter;
int cap;
};
array.cpp:
#include "array.h"
AR::AR() {
counter = 0;
cap = 2;
point = new string[cap];
}
AR::AR(int no_of_cells) {
counter = 0;
cap = no_of_cells;
point = new string[cap];
}
AR::AR(const AR& Original) {
counter = Original.counter;
cap = Original.cap;
point = new string[cap];
for(int i=0; i<counter; i++) {
point[i] =Original.point[i];
}
}
// AR::~AR() {
// delete [ ]point;
//}
ostream& operator<<(ostream& out, AR& Original) {
cout << "operator<< has been invoked\n";
for (int i=0; i< Original.counter; i++) {
out << "point[" << i <<"] = " << Original.point[i] << endl;
}
return out;
}
AR& AR::operator=(const AR& rhs) {
cout << "operator= invoked\n";
if (this == &rhs)
return *this;
point = rhs.point;
return *this;
}
void ReadF(const int neocap, string& neopoint, int neocounter) {
ifstream in;
in.open("sample_strings.txt"); //ifstream in; in.open("sample_data.txt");
if (in.fail())
cout<<"sample_data not opened correctly"<<endl;
while(!in.eof() && neocounter < neocap) {
in >> neopoint[neocounter];
neocounter++;
}
in.close();
}
ifstream& operator>>(ifstream& in, AR& Original) {
Original.counter = 0;
while(!in.eof() && Original.counter < Original.cap) {
in >> Original.point[Original.counter];
(Original.counter)++;
}
return in;
}
It appears you are missing AR:: in the ReadF definition.
On second thought you are reading into an index of neopoint that likely isn't allocated yet. You could change ReadF to read:
void ReadF(const int neocap, string& neopoint,int neocounter)
{
ifstream in;
in.open("sample_strings.txt"); //ifstream in; in.open("sample_data.txt");
if (in.fail())
{
cout<<"sample_data not opened correctly"<<endl;
return;
}
neopoint.resize(neocap);
while(neocounter < neocap && in >> neopoint[neocounter])
{
neocounter++;
}
in.close();
}
Although you probably want to look into stringstream
std::ifstream in("sample_strings.txt");
if (in)
{
std::stringstream buffer;
buffer << in.rdbuf();
in.close();
inneopoint= buffer.str();
}