operator overloading opertator + cant convert from pointer to const - c++

i have a sparse matrix that is created with two arrays and each array index have a linked list the non zero numbers are in there including the i and j indexs
the header
class MNode {
public:
double _data;
int _indexI, _indexJ; // the place of the node in the matrix
// clarification: _nextRow is a pointer to the next columns in the row
MNode* _nextRow, *_nextCol;
MNode(double data, int i, int j);
};
private:
string _type;
MNode** _rowHead, **_colHead;
int _rowSize, _colSize;
int _elemNum;
void setValue(int, int, double);
void removeElement(int, int);
void insertNode(MNode*);
bool IsExist(int, int);
void setElementByType(int i, int j, double data);
public:
// construct a 'rows X cols' matrix.
SMatrix(int rows, int cols,string type);
// set the (i,j) element to be 'data'
void setElement(int i, int j, double data);
// destroy this matrix.
~SMatrix();
double getElement(int, int);
friend std::ostream& operator<<(std::ostream& os, const SMatrix& mat);
SMatrix& operator = (const SMatrix& other);
SMatrix & operator+(const SMatrix & other) const;
};
the cpp here is the overloading + function i get an erorr
cannot convert this pointer to const SMatrix to Smatrix&
SMatrix &SMatrix::operator +(const SMatrix& other) const {
SMatrix temp(3, 3, "any") ;
if (other._rowSize == this->_rowSize&&other._colSize == this->_colSize&&other._type == this->_type) {
for (int j = 0; j < other._colSize; j++) {
for (int i = 0; i < other._rowSize; i++) {
temp.setElement(i, j, (other.getElement(i, j) + this->getElement(i, j)));
}
}
}
return temp;
}
here is the contructor
SMatrix::SMatrix(int rows, int cols,string matType )
{
_type = matType;
_rowSize = rows;
_colSize = cols;
_elemNum = 0;
_rowHead = new MNode*[rows];
if (!_rowHead)
{
cout << "allocation error";
exit(1);
}
_colHead = new MNode*[cols];
if (!_colHead)
{
cout << "allocation error";
exit(1);
}
for (int i = 0; i < rows; i++)
{
_rowHead[i] = NULL;
}
for (int i = 0; i < cols; i++)
{
_colHead[i] = NULL;
}
}
iam not sure what i need to do the signature of the function is given and cant be chanbged any idea?

You've declared other to be a reference to const:
SMatrix & operator+(const SMatrix & other) const;
^^^^^
You call the member function getElement on that reference:
temp.setElement(i, j, (other.getElement(i, j) + this->getElement(i, j)));
^^^^^^^^^^^^^^^^
You've declared getElement to be non-const:
double getElement(int, int);
^
You may only call const member functions on const references.
the signature of the function is given and cant be chanbged any idea?
If the signature of getElement can't be changed, then you've been dealt a badly written signature. There should be no good reason why a getter couldn't be const. That said, since you're within the class, you can access all members directly without using a getter.
There's another bug. You've declared operator+ to return a reference.
SMatrix &SMatrix::operator +(const SMatrix& other) const
^
But you return a local automatic variable temp:
SMatrix temp(3, 3, "any") ;
// ...
return temp;
Automatic variables are destroyed at the end of the function. Therefore the returned reference will always be dangling and any use of it would have undefined behaviour.
the signature of the function is given and cant be chanbged any idea?
If the signature of operator+ can't be changed, then you've been dealt a badly written signature. The function really should return by value. There's no sensible solution that could return a reference. Using a static local would technically work, but that has some limitations on usage that aren't apparent from the interface.

Related

c++ 2 overloads have similar conversions depending on whether the operator is a member function or a global one

Consider a simple vector class realization:
#include <algorithm>
class Vector {
public:
Vector(int _elementsCount)
: elementsCount(_elementsCount)
, elements(new float[_elementsCount])
{}
~Vector() {
delete[] elements;
}
Vector(const Vector& rhs) {
elementsCount = rhs.size();
elements = new float[elementsCount];
for (int i = 0; i < elementsCount; ++i)
(*this)[i] = rhs[i];
}
float& operator [](int i) {
return elements[i];
}
float operator [](int i) const {
return const_cast<Vector&>(*this)[i];
}
int size() const {
return elementsCount;
}
/*// Dot product
float operator *(const Vector& v) {
float res = 0;
for (int i = 0; i < size(); ++i)
res += (*this)[i] * v[i];
return res;
}*/
private:
int elementsCount;
float* elements;
};
// Multiplication by a scalar
Vector operator *(const Vector& v, float k) {
Vector res(v.size());
for (int i = 0; i < v.size(); ++i)
res[i] = v[i] * k;
return res;
}
// Dot product
float operator *(const Vector& v1, const Vector& v2) {
float res = 0;
for (int i = 0; i < std::min(v1.size(), v2.size()); ++i)
res += v1[i] * v2[i];
return res;
}
void main()
{
Vector v(2);
v * 3; // ambiguous
}
This code compiles. But if we uncomment * operator realization in the class and comment its global realization (dot product function), then there will be an error "'Vector::operator *': 2 overloads have similar conversions", because there is an ambiguity: whether to call the multiplication by a scalar or to interpret 3 as an argument to a parametrized constructor and to call the dot product. This makes sense. But I don't get what's the difference of declaring the * operator as a member function or as a global function. I thought they should be the same in the example like above, but it's not the case.
Added. The thing I most interested in is not how to avoid the ambiguity, but why there is an ambiguity in one case (when * is declared as a member) and there is no one in the other (when * is declared as a global function).
You need to make your constructor explicit:
explicit Vector(int _elementsCount) { ... }
The reason for the ambiguity is that the compiler can't decide whether it should implicitly convert a int value to a Vector and invoke Vector::operator*, or implicitly convert a int value to a float and use operator*(const Vector&, float).
By using explicit, such conversions are forbidden, and you must use Vector(3) if you want "3" to be a Vector.
As a side-note, you should make the operator const, since it does not modify the object. Making it const will also allow it to be used with a const Vector:
float operator *(const Vector& v) const { ... }
Beware that will still conflict with your other overload:
float operator *(const Vector& v1, const Vector& v2)
There is no reason to have both. Choose either the member function or the global function and remove the other.

c++ - run on an object, operator overloading () with index

I have a class to represent two-dimensional array and I want to use () operator for example,
Array arr;
arr(2,5) = 17; // I want to assign 17 as element in 2nd row and 5th column.
I tried something like that: (but is not working)
void operator(int m, int n)(int num) {
int m, n;
p[m][n] = num;
}
i have an operator = (this working):
void operator=(const Array& other) const {
for (int i = 0; i < DIM; i++) {
for (int j = 0; j < DIM; j++) {
p[i][j] = other.p[i][j];
}
}
}
Array class has T** as private member.
How can I overload () operator to access elements in array
Thank You!
You need to build something like
int& operator()(int m, int n)
which returns a reference to the array element, that you can modify through that reference at the calling site.
Don't forget to build the const overload
const int& operator()(int m, int n) const
so you can use similar syntax at a call site for element access for a const object.
Finally, for your assignment operator, you ought not make it const (have you made p mutable?), and you should return a reference to self to help compound assignment:
Array& operator=(const Array& other){
// Your existing code
return *this;
}
Reference: http://en.cppreference.com/w/cpp/language/copy_assignment

No viable overloaded operator[] for a const type

I have a type BigInt which stores large numbers as an array of digits (0-9) in a char array called privately m_digitArray.
I was trying to overload the array access operator [] and it worked, both for accessing and assigning char values.
I then tried to overload the assignment operator =, it gave me the above-mentioned error.
Where am I going wrong? How can I transfer (essentially copy) values from one BigInt object to another?
Here's the code
BigInt.h
#include <iostream>
using namespace std;
class BigInt{
private:
// Object Data
char *m_digitArray;
unsigned int m_digitArraySize;
bool m_isPositive;
// Private Methods
int getNumOfDigits(int number);
void reverseArray(char arr[], int start, int end);
public:
// Constructors
BigInt();
BigInt(int numOfDigits);
BigInt(const BigInt &bi);
BigInt(const string &number);
// Access
int getSize() const;
bool isPositive() const;
char &operator [] (int);
};
BigInt.cpp
int BigInt::getSize() const {
return m_digitArraySize;
}
bool BigInt::isPositive() const {
return m_isPositive;
}
char & BigInt::operator [] (int i){
if(i > m_digitArraySize-1){
cerr << "Error: Array index out of bounds!" << endl;
exit(0);
}
return m_digitArray[i];
}
BigInt & BigInt::operator = (const BigInt &rhs){
if(this != &rhs){
m_digitArraySize = rhs.getSize();
m_isPositive = rhs.isPositive();
m_digitArray = new char[m_digitArraySize];
for (int i = 0; i < m_digitArraySize; ++i){
m_digitArray[i] = rhs[i];
}
}
return *this;
}
Error
BigInt.cpp:129:25: error: no viable overloaded operator[] for type 'const BigInt'
m_digitArray[i] = rhs[i];
~~~^~
BigInt.cpp:114:16: note: candidate function not viable: 'this' argument has type
'const BigInt', but method is not marked const
char & BigInt::operator [] (int i){
^
1 error generated.
Thank you #DeiDei for pointing out I needed two separate overloads. I guess I was misreading the error prompt.
Fixed it by adding this to the header file:
char operator [] (int) const;
and this as the implementation:
char BigInt::operator [] (int i) const{
if(i > m_digitArraySize-1){
cerr << "Error: Array index out of bounds!" << endl;
exit(0);
}
return m_digitArray[i];
}

Returning deep copies of objects when overloading the = operator

So I making a container class for integers and I want to overload the = operator so that I can return a deep copy of the object. My code works but the two objects point to the same address. This is the main.cpp file:
int main (int argc, const char * argv[]) {
IntList cArray(5);
for (int i = 0; i < cArray.getLength(); i++) {
cArray[i] = (i + 1) * 10;
}
using namespace std;
for (int i = 0; i < cArray.getLength(); i++)
cout << cArray[i] << " ";
cout << endl << popped << endl;
IntList cArray2(4);
for (int i = 0; i < cArray2.getLength(); i++)
cArray2[i] = i * 5;
cArray2 = cArray;
cArray2[2] = 1000;
for (int i = 0; i < cArray.getLength(); i++)
cout << cArray[i] << " ";
cout << endl;
for (int i = 0; i < cArray2.getLength(); i++)
cout << cArray2[i] << " ";
cout << endl;
return 0;
}
This is the header file for the IntList class:
class IntList {
private:
int _length;
int* _data;
public:
IntList(int length);
~IntList();
void erase();
void reallocate(int length); // Faster way to call erase() and resize()
void resize(int length);
void insert(int value, int index);
void prepend(int value);
void append(int value);
int pop(int index);
void removeBefore(int index); // Exclusive
void removeAfter(int index); // Exclusive
int getLength();
int indexOf(int value);
int& operator[](int index);
IntList operator=(IntList* source);
};
And this is the implementation of IntClass's operator=() method:
IntList IntList::operator=(IntList* source) {
_length = source->getLength();
reallocate(_length);
for (int i = 0; i < _length; i++) {
_data[i] = (*source)[i];
}
return *this;
}
You're not working with pointers to IntList - operator= typically takes a const & and returns a reference to the instance being assigned to.
IntList & IntList::operator=(IntList const & source) {
...
return *this;
}
Remember that you also need a copy constructor: IntList(IntList const & source)
You can make an operator= which takes a pointer to IntList - that would only work if you did something like this:
IntList l1;
IntList l2;
l1 = &l2;
This isn't typical usage, and you should rather be explicit if you require this, use e.g. void IntList::copyFrom(IntList const *) in this case.
Other changes you should make:
Add this:
int operator[](int index) const;
Make these const:
int getLength() const;
int indexOf(int value) const;
Because your assignment operator takes a pointer to an IntList, you would need to call it like this:
cArray2 = &cArray;
Your example code is using the default assignment operator generated by your compiler. Your assignment operator should have this declaration instead:
IntList& IntList::operator=(IntList const& source)
IntList IntList::operator=(IntList* source)
Wrong signature for operator=, as it's parameter type is a pointer to IntList
Correct signature is this:
IntList & IntList::operator=(const IntList & source) //reference of source!
//^^^ note this ^^^ note this as well!
That is, make both parameter type as well as return type reference.
Your operator needs the signature IntList& operator=(const IntList& source);. Note the reference instead of the pointer, and that you must RETURN by reference as well to allow assignment chaining. When you pass it by pointer anywhere implicit assignment is required the compiler-generated shallow copy assignment operator will be used.
EDIT: You also need to make getLength const so that it's able to be called inside the assignment operator.

How do I go about overloading C++ operators to allow for chaining?

I, like so many programmers before me, am tearing my hair out writing the right-of-passage-matrix-class-in-C++. I have never done very serious operator overloading and this is causing issues. Essentially, by stepping through
This is what I call to cause the problems.
cMatrix Kev = CT::cMatrix::GetUnitMatrix(4, true);
Kev *= 4.0f;
cMatrix Baz = Kev;
Kev = Kev+Baz; //HERE!
What seems to be happening according to the debugger is that Kev and Baz are added but then the value is lost and when it comes to reassigning to Kev, the memory is just its default dodgy values. How do I overload my operators to allow for this statement?
My (stripped down) code is below.
//header
class cMatrix
{
private:
float* _internal;
UInt32 _r;
UInt32 _c;
bool _zeroindexed;
//fast, assumes zero index, no safety checks
float cMatrix::_getelement(UInt32 r, UInt32 c)
{
return _internal[(r*this->_c)+c];
}
void cMatrix::_setelement(UInt32 r, UInt32 c, float Value)
{
_internal[(r*this->_c)+c] = Value;
}
public:
cMatrix(UInt32 r, UInt32 c, bool IsZeroIndexed);
cMatrix( cMatrix& m);
~cMatrix(void);
//operators
cMatrix& operator + (cMatrix m);
cMatrix& operator += (cMatrix m);
cMatrix& operator = (const cMatrix &m);
};
//stripped source file
cMatrix::cMatrix(cMatrix& m)
{
_r = m._r;
_c = m._c;
_zeroindexed = m._zeroindexed;
_internal = new float[_r*_c];
UInt32 size = GetElementCount();
for (UInt32 i = 0; i < size; i++)
{
_internal[i] = m._internal[i];
}
}
cMatrix::~cMatrix(void)
{
delete[] _internal;
}
cMatrix& cMatrix::operator+(cMatrix m)
{
return cMatrix(*this) += m;
}
cMatrix& cMatrix::operator*(float f)
{
return cMatrix(*this) *= f;
}
cMatrix& cMatrix::operator*=(float f)
{
UInt32 size = GetElementCount();
for (UInt32 i = 0; i < size; i++)
{
_internal[i] *= f;
}
return *this;
}
cMatrix& cMatrix::operator+=(cMatrix m)
{
if (_c != m._c || _r != m._r)
{
throw new cCTException("Cannot add two matrix classes of different sizes.");
}
if (!(_zeroindexed && m._zeroindexed))
{
throw new cCTException("Zero-Indexed mismatch.");
}
for (UInt32 row = 0; row < _r; row++)
{
for (UInt32 column = 0; column < _c; column++)
{
float Current = _getelement(row, column) + m._getelement(row, column);
_setelement(row, column, Current);
}
}
return *this;
}
cMatrix& cMatrix::operator=(const cMatrix &m)
{
if (this != &m)
{
_r = m._r;
_c = m._c;
_zeroindexed = m._zeroindexed;
delete[] _internal;
_internal = new float[_r*_c];
UInt32 size = GetElementCount();
for (UInt32 i = 0; i < size; i++)
{
_internal[i] = m._internal[i];
}
}
return *this;
}
Your operators + and * must return by value, not by reference. You're returning a temporary variable by reference. Also, you're arguments are passed by value when it should be a const reference:
cMatrix cMatrix::operator+(cMatrix const& m)
{
cMatrix matrix(*this);
matrix += m;
return matrix;
}
cMatrix cMatrix::operator*(float f)
{
cMatrix matrix(*this);
matrix *= m;
return matrix;
}
You should take a look at Boost.Operators. This would let you implement only operator*= and operator+= and automatically provide correct implementations for operator+ and operator*.
PS: If you implement your matrix class just for the learning experience, don't hesitate to look at other implementations like the Matrix Template Library.
PPS: If you don't want to use boost, or if you just want to understand the best practice, take a look at Boost.Operator and do what they do.
IMO the canonical form of overloading addition is this:
class X {
public:
X& operator+=(const X& rhs) { /*add rhs to *this*/ }
};
inline X operator+(X lhs, const X& rhs) {lhs+=rhs; return lhs;}
The same goes for -, *, /, where applicable.
Note that + returns a copy, not a reference. That's important, because A+B creates a new value, so it cannot return a reference to an existing one.
Also, it is a free function. IMO it's best to implement those of the binary operators which can be implement either as a member or as a free function as free functions, if they treat their operands symmetrically (as does +), and as member functions, if they treat their operands asymmetrically (as +=, which changes its left argument. If you implement operator+ as a member, you will have to make the function const (X operator+(const X& rhs) const), so that it can be invoked for constant elements on the left side.