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.
Related
I am writing an assignment that requires me to implement my own (basic) vector class. One unusual requirement, is that we must provide a function which gives the sum of all elements in the vector. This function should cache the sum, so subsequent calls can be answered in constant time if the vector has not changed.
The problem I am having is trying to figure out when it has changed.
#include <iostream>
class MyVector {
int* v;
int size;
int totalSum;
bool upToDate;
public:
MyVector(int size) : size{size}, totalSum{0}, upToDate{false} {
v = new int[size];
for(int i = 0; i < size; i++) {
v[i] = 0;
}
}
// Set - should only be called as an lvalue
int& operator[](unsigned int i) {
upToDate = false;
std::cerr << "Set\n";
return v[i];
}
// Get - should only be called as an rvalue
int operator[](unsigned int i) const {
std::cerr << "Get\n";
return v[i];
}
// Get sum of array -- result is cached for performance
int sum() {
if(!upToDate) {
upToDate = true;
totalSum = 0;
for(int i = 0; i < size; i++) {
totalSum += v[i];
}
}
return totalSum;
}
};
int main() {
MyVector mv(3);
mv[0] = 1;
mv[1] = 2;
mv[2] = 3;
std::cout << "Sum " << mv.sum() << "\n";
int first = mv[0];
std::cout << "First element is " << first << "\n";
std::cout << "Sum " << mv.sum() << "\n";
}
I've provided two overloaded versions of the [] operator -- one for getting and one for setting. Whenever the setting version of the operator is invoked, I assume that the vector is being changed.
# Output
Set
Set
Set
Sum 6
Set
First element is 1
Sum 6
However, it seems the setting version of the operator is always being called, even when it is being used as an rvalue.
How do I overload the [] operator correctly to distinguish between its use for getting and setting?
Instead of returning a reference to the stored int directly, you can return a thin proxy wrapper around that reference, which can watch for changes. In the majority of cases, the compiler should inline it and optimize it away (you can try to benchmark it and compare).
The wrapper class:
class Item {
int &value;
MyVector &myVector;
public:
Item(int &value, MyVector &myVector) : value(value), myVector(myVector) {}
Item& operator=(int newvalue) {
std::cerr << "Set\n";
value = newvalue;
myVector.upToDate = false;
return *this;
}
// TODO: Reimplement also operators like +=, -=, etc
// You can use boost helpers for that.
operator int() const {
std::cerr << "Get\n";
return value;
}
};
Changes to MyVector:
class MyVector {
// ...
Item operator[](unsigned int i) {
return Item(v[i], *this);
}
const int operator[](unsigned int i) const {
std::cerr << "Const Get\n";
return v[i];
}
// ...
}
It can be used exactly the same way:
int main() {
MyVector mv(3);
mv[0] = 1;
mv[1] = 2;
mv[2] = 3;
std::cout << "Sum " << mv.sum() << "\n";
int first = mv[0];
std::cout << "First element is " << first << "\n";
std::cout << "Sum " << mv.sum() << "\n";
}
I am not sure what I am doing wrong here but I used Google and found almost the identical code to mine but they did not claim an error. Our assignment is to overload the insertion operator. The problem is that I get an error in the driver for every time I pass SAM or JOE. The error states: Error 2 error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'MyVector' (or there is no acceptable conversion).
Any help is appreciated. Please note that I have not completed this assignment and if another function doesn't seem right, it may be because I haven't work on it.
Thanks in advance.
Driver.cpp
#include <iostream>
#include "MyVector.h"
using namespace std;
// the printV function
// used to test the copy constructor
// parameter: a MyVector object
void printV(MyVector);
int main()
{
cout << "\nCreating a vector Sam of size 4.";
MyVector sam(4);
cout << "\nPush 12 values into the vector.";
for (int i = 0; i < 12; i++)
sam.push_back(i);
cout << "\nHere is sam: ";
cout << sam;
cout << "\n---------------\n";
cout << "\nCreating a vector Joe of size 4.";
MyVector joe(4);
cout << "\nPush 6 values into the vector.";
for (int i = 0; i < 6; i++)
joe.push_back(i * 3);
cout << "\nHere is joe: ";
cout << joe;
cout << "\n---------------\n";
cout << "\nTest the overloaded assignment operator \"joe = sam\": ";
joe = sam;
cout << "\nHere is sam: ";
cout << sam;
cout << "\n---------------\n";
cout << "\nHere is joe: ";
cout << joe;
cout << "\n---------------\n";
// pass a copy of sam by value
printV(sam);
cout << endl;
system("PAUSE");
return 0;
}
void printV(MyVector v)
{
cout << "\n--------------------\n";
cout << "Printing a copy of a vector\n";
cout << v;
}
My Vector.h
#pragma once
class MyVector
{
private:
int vSize;
int vCapacity;
int* vArray;
void grow();
public:
MyVector();
MyVector(int n);
MyVector(const MyVector& b);
int size() const;
int capacity() const;
void clear();
void push_back(int n);
int& at(int n) const;
MyVector& operator=(const MyVector& rho);
~MyVector();
};
MyVector.cpp
#include "MyVector.h"
#include <iostream>
using namespace std;
MyVector::MyVector()
{
vArray = nullptr;
vSize = 0;
vCapacity = 0;
}
MyVector::MyVector(int n)
{
vArray = new int[vCapacity];
vSize = 0;
vCapacity = n;
}
MyVector::MyVector(const MyVector& b)
{
vSize = b.size();
vArray = new int[vSize];
for (int i = 0; i < b.size(); i++)
{
this->vArray[i] = b.vArray[i];
}
}
int MyVector::size() const
{
return vSize;
}
int MyVector::capacity() const
{
return vCapacity;
}
void MyVector::clear(void)
{
if (vArray != nullptr)
{
delete[] vArray;
vArray = nullptr;
vSize = 0;
vCapacity = 0;
}
}
void MyVector::push_back(int n)
{
if (vCapacity == 0)
{
vCapacity++;
int* tmp = new int[vCapacity];
delete[] vArray;
vArray = tmp;
}
if (vSize >= vCapacity)
{
grow();
}
vArray[vSize] = n;
vSize++;
}
void MyVector::grow()
{
vCapacity = vCapacity + vCapacity;
int* tmp = new int[vCapacity];
for (int i = 0; i < vSize; i++)
{
tmp[i] = vArray[i];
}
delete[] vArray;
vArray = tmp;
}
int& MyVector::at(int index) const
{
if (index >= 0 && index<vSize)
{
return vArray[index];
}
else
{
throw index;
}
}
MyVector& MyVector::operator=(const MyVector& rho)
{
// test for self assignment
if (this == &rho)
return *this;
// clean up array in left hand object (this)
delete[] this->vArray;
// create a new array big enough to hold right hand object's data
vSize = rho.size();
this->vArray = new int[vSize];
// copy the data
for (int i = 0; i < rho.size(); i++)
{
this->vArray[i] = rho.vArray[i];
}
// return this object
return *this;
}
MyVector::~MyVector()
{
if (vArray != nullptr)
{
clear();
}
}
ostream& operator<<(ostream& out, const MyVector& rho)
{
for (int i = 0; i < rho.size(); i++)
{
out << rho.at(i);
}
return out;
}
Declare std::ostream& operator<<(std::ostream& out, const MyVector& rho) in My Vector.h. That function is used in Driver.cpp, therefore Driver.cpp must know about it.
If you do this, you should also #include <ostream> in My Vector.h.
To be able to use your offending operator<<() in main(), there needs to be a declaration of it visible to the compiler when compiling Driver.cpp.
That means you need to declare your operator<<() in MyVector.h.
Having the definition of operator<<() in MyVector.cpp is fine, but that is not visible to the compiler when compiling Driver.cpp
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.
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.
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...).