Having issues with overloading C++ operators - c++

I'm having some issues understanding this concept. In the main.cpp file, we have a function as follows:
void TestComparison()
{
MyFloat X, Y;
cout << "\n\n============ Testing \"==\" for MyFloat ================\n";
do
{
cout << "\nEnter X ==> ";
X.Read();
cin.ignore(1000, '\n'); // Discard all chars in input stream.
cout << "\nEnter Y ==> ";
Y.Read();
cin.ignore(1000, '\n'); // Discard all chars in input stream.
cout << "\n\n";
if ( X == Y )
{
X.Write(); cout << " is equal to "; Y.Write();
}
else
{
X.Write(); cout << " is NOT equal to "; Y.Write();
}
}
while ( SpaceBarToContinue() );
}
This is the class I'm writing:
class MyFloat
{
enum {MAXDIGIT=20};
char Number[MAXDIGIT+1];
char NumberOfDigits;
public:
friend void AssignValue(MyFloat& X);//remove after the program works
MyFloat();
int Digits();
int MaxDigits();
void Read();
void Write();
MyFloat operator + (MyFloat x);
int operator== (MyFloat x);
};
Here is my == overload function stub:
int MyFloat::operator== (MyFloat x)
{
int Flag=0;
return 1;
}
The only purpose of this is to compare two an array of objects X and Y. They are passed into a == overloaded function. I'm supposed to write the algorithm that compares them. I know how to write the algorithm that compares these two character arrays, thats not the issue, but what I'm failing to understand is how both X and Y get into the the overloaded function to compare them? In the main, the code ( X == Y ) is used to obtain a 0 or 1. How are X and Y passed into the function?
For instance, I would assume my function stub would need to be rewritten with 2 parameters:
int MyFloat::operator== (MyFloat x, MyFloat y)
{
int Flag=0;
return 1;
}
But doing this produces an error back in the main during the function call of ( X == Y ) that states 'Overload "operator==" must be a binary operator (has 3 parameters)'
So I'm totally confused on how to get both Objects of MyFloat into the function to compare them. I'm still fairly new to programming (5-6 months of learning), any plain and simple answers are greatly appreciated.

When you write:
if(a == b)
what it really means is:
if(a.operator==(b))
So in your method:
bool MyFloat::operator==(const MyFloat &x) const
{
// x is b in call above
// (*this) is a in call above
// Your class invariant should guarantee this:
// assert(x.NumberOfDigits < MAX_DIGITS);
// In the scope of your class' methods:
// NumberOfDigits corresponds to this->NumberOfDigits
// Number corresponds to this->Number
if(x.NumberOfDigits != NumberOfDigits) return false;
// Same as: if(x.NumberOfDigits != this->NumberOfDigits) return false;
return strncmp(x.Number, Number, NumberOfDigits) == 0;
// Same as: return strncmp(x.Number, this->Number, this->NumberOfDigits) == 0;
}
Note that I changed the signature of your method. The correct signature returns a bool and takes a const (because you don't want to change the parameter) reference (avoid copying a big object) as parameter. The method is (and must be) const because it's not supposed to modify the object and it must be callable on a const object.
Note that it is possible to define the operator as a non-member function (i.e outside of the class) with the following signature:
bool operator==(const MyFloat &a, const MyFloat &b)

You should use this pointer. For more information: Source
bool MyFloat::operator==(const MyFloat& x) const
{
for(int i = 0; i < x.MaxDigits; ++i)
{
if(x[i] != (*this)[i])
return false;
}
return true;
}

member functions (including overloaded operators) have an implicit this parameter passed in. In your case since you are using a member version of operator== you should only need one parameter the other is this.

Related

compiler gives invalid operands to binary expression error even if there is an overloaded stream insertion operator

I'm trying to learn operator overloading and I get a below error
error: invalid operands to binary expression ('std::ostream' (aka 'basic_ostream<char>') and 'Coefficient')
cout << (c + 4) << endl ;
I mentioned the line that causes the compiler to give an error. (last line in the main)
#include <iostream>
#include <ostream>
using namespace std ;
class Coefficient {
private:
double myValue ;
mutable int myAccesses ;
public:
Coefficient (double initVal) {
myValue = initVal ;
myAccesses = 0 ;
}
double GetValue (void) const {
myAccesses++ ;
return myValue ;
}
bool operator= (double v) {
myAccesses++ ;
if (v < 0 || v > 1) {
return false ;
}
myValue = v ;
return true ;
}
bool operator+= (double addval) {
return addValue(addval) ;
}
bool operator-= (double subval) {
return addValue(-subval) ;
}
bool operator= (char * str) {
if(!strcmp(str, "default")) {
return operator=(0.5) ;
} else if (!strcmp(str, "max")) {
return operator=(0.0) ;
} else if (!strcmp(str, "min")) {
return operator=(1.0) ;
} else {
return false ;
}
}
Coefficient operator+ (double d) {
Coefficient sum{ this->myValue + d} ;
return sum ;
}
private:
bool addValue (double v) {
myAccesses++ ;
if (myValue + v < 0 || myValue + v> 1) {
return false ;
}
myValue += v ;
return true ;
}
} ;
Coefficient operator+ (double leftval, Coefficient rightval) {
return rightval + leftval ;
}
ostream & operator<< (ostream & output, Coefficient & holder) {
output << (holder.GetValue()) ;
return output ;
}
int main (void) {
Coefficient c{0.5} ;
cout << c << "\t";
c = 0.75 ;
cout << c << endl ;
c = const_cast<char *>("max") ;
cout << c << endl ;
c = const_cast<char *>("default") ;
cout << c << endl ;
c = (c + 4) ;
cout << c << endl ;
cout << (c + 4) << endl ; // compiler gives error because of this line
}
I do overload the stream insertion operator and addition operator, and when I delete the last line, I can use my custom class with stream insertion operator and it prints a value.
As you can see at the end of the main, when I assigned the result of the summation to the variable, and then use the variable with stream insertion operator, I could print the value. But when I tried to use summation without assigning the variable, it gives an error.
Why does the compiler give that error? Why the compiler does not find proper overloaded function without assigning to the variable?
I am using mac os big sur. I use clang version 13.0.0
The definition of your stream output operator accepts a reference to a Coefficient:
ostream & operator<< (ostream & output, Coefficient & holder) {
output << holder.GetValue();
return output;
}
This works in the naive case, when you have some variable of type Coefficient and you output it.
cout << c; //<-- c is an lvalue
But there's a subtle thing going on here. The reference is what's called an lvalue -- that is, something that can be modified. The reason why this works is because you're allowed to modify c because it's non-const and exists in the stack in your main function.
Now, consider the problem call:
cout << (c + 4); //<-- (c + 4) is an rvalue
The way c + 4 was created was via a value returned from your operator+ overload. The return value is a temporary, because it's not actually being stored in a variable anywhere. Instead, it's created as a temporary that is used as an operand. The temporary is what's called an rvalue. The C++ standard prevents a program from holding non-const references to rvalues (a slight exception to this being rvalue references, which you are not using here and are not appropriate for this problem).
And so, the compiler error here is an overload resolution issue. You made a temporary value with c + 4 but there is no function that can take it as an argument, nor is there any way to automatically convert it to match any other operator overload.
To correct the issue, you need to either copy it (make the parameter a non-reference), or pass it as a const reference. Usually, the latter is preferable:
ostream & operator<< (ostream & output, const Coefficient & holder) {
output << holder.GetValue();
return output;
}
This will fix the overload resolution problem, and since you have already correctly declared .GetValue() as const there should be no other issues. But, if you had not made that GetValue function const, you would get an error.
Basic rules of thumb for const-correctness:
if a function will not modify a parameter passed as a reference, make the reference const.
if a member function will not modify the object, make the function const.
(c + 4) is an rvalue (in type Coefficient&&) and it cannot be captured by Coefficient&).
Try to add another overload function like:
ostream & operator<< (ostream & output, Coefficient && holder);

Why do variables in my struct appear as const? [duplicate]

This question already has answers here:
Range-based for with brace-initializer over non-const values?
(5 answers)
Closed 2 years ago.
So I have a struct to make storing and comparing of x y coordinates easier.
I'm trying to get two sets of coordinates, so four numbers in total, as input from the user and stored in two 'Card_position' structs but I can't seem to get it to work from within the for loop.
On the for loop line it gives me an error: binding value of type 'const int' to reference to type 'int' drops 'const' qualifier
even though nothing has a const qualifier.
My solution was to just do it without the loop but I would like to know the real solution.
Here's a snippet of where the error is coming from.
Card_position guess1{0, 0};
Card_position guess2{0, 0};
while (true)
{
cout << player.get_name() << ": " << INPUT_CARDS;
string input = "";
for (int& guess : {guess1.x, guess1.y, guess2.x, guess2.y} )
{
cin >> input;
if(input == "q")
return 1;
guess = stoi_with_check(input);
}
I tried without the reference but then it just won't save the values into the structs. Any solutions?
here is the struct definition:
struct Card_position
{
int x;
int y;
bool operator ==(Card_position& other)
{
return (this->x == other.x) && (this->y == other.y);
}
bool operator <(Card_position& minimum)
{
return (this->x < minimum.x) || (this->y < minimum.y);
}
bool operator >(Card_position& max)
{
return (this->x > max.x) || (this->y > max.y);
}
};
The problem is the initializer list ({guess1.x, guess1.y, guess2.x, guess2.y}) that stores those ints internally as const, and then the int & cannot bind to that value. You can get around this by using an `std::reference_wrapper':
for (auto guess : {std::ref(guess1.x), std::ref(guess1.y), std::ref(guess2.x), std::ref(guess2.y)} )
{
cin >> input;
if(input == "q")
return 1;
guess = stoi_with_check(input);
}
The guess is then intialized by a copy of that wrapper, that can be manipulated and will be able to edit the value it points to. (Alternatively, you can use pointers like this:
for (int* guess : {&guess1.x, &guess1.y, &guess2.x, &guess2.y} )
{
cin >> input;
if(input == "q")
return 1;
*guess = stoi_with_check(input);
}
Because an initializer list gives a const iterator.
This is creating an initializer list:
{guess1.x, guess1.y, guess2.x, guess2.y}
I’m not really sure what the point of this construction is anyways because assigning to these values makes little sense, since you can't retrieve them after the for loop.
Maybe you are looking for something like this?
std::vector<int> v{guess1.x, guess1.y, guess2.x, guess2.y};
for (int& guess : v)
{ // ...

2D iterator for loop

I'm having issues implementing an iterator class in regards to .end(). The problem I'm running into is when I try to use a for loop with my iterator class; it's currently stopping just before the last element in a 2D vector. However, I want it to go one element past the last element without causing a compiler error, and to include the last character in the print statement.
main.cpp
// file contents
// aaa
// bbb
// cce
// factory method (adds file contents to 2D <char> vector)
Base *a = Base::create("file");
cout << *a; // overloaded '<<'
Prints
a a a b b b c c e
Now, when I use a for loop with my iterator class, it doesn't include the last character.
for(auto it = a->begin(); it != a->end(); it++)
cout << *it << ' ';
Prints
a a a b b b c c
The .end prints the following
Base::iterator it = aa->end();
cout << *it << '\n';
// prints e
When I try a while loop, it includes the last character.
// Note: my iterator class is a nested class inside Base class.
const Base::iterator et = a->begin();
int i = 0;
while(i < 13) {
cout << *et << ' ';
et++;
}
Prints
a a a b b b c c e e e e e
I understand that a->end() is supposed to point just past the last character, but I don't understand how to implement that. When I increment past the last value in my operator++(int), it displays a segmentation fault. Currently, my overloaded increment method stops at the last character and doesn't go past it. With that said, how do I implement my ++(int) method to include the last element when printing from a for loop? Am I supposed to add a null element to the vector or something like that?
Inside Base.cpp
// This function is whats causing the issue. I know it looks ugly.
Base::iterator Base::iterator::operator++(int) {
// base is a Base *, x and y are coordinates for 2D vector
Base::iterator temp(base, x, y); // save value
// if iterator has not reached end
if( !((x == base->vec.size()-1) && (y == base->vec[0].size()-1)) )
{
// if y < row size
if(y < base->vec[0].size()-1)
y++;
// if y has reached end of row, increment x and start y on a new row
else if(x < base->vec.size() && y == base->vec[0].size()-1) {
y=0;
x++;
}
}
return temp;
}
Base::iterator Base::begin() {
return Base::iterator(this, 0, 0);
}
Base::iterator Base::end() {
return Base::iterator(this, vec.size()-1, vec[0].size()-1);
}
Rest of Base.cpp
#include "Base.h"
using namespace std;
// Factory method (instantiates 2D vector with file contents)
Base *Base::create(string filename) {/*removed irrelevant code */}
Base::~Base(){}
// prints 2D vector
ostream &operator<<(ostream &os, const Base &val){/*removed irrelevant code*/}
Base::iterator::iterator(Base *b, int m, int n): base(b), x(m), y(n) {}
Base::iterator::~iterator(){}
// returns a character inside 2D vector
char &Base::iterator::operator*() const {
return base->vec[x][y];
}
bool Base::iterator::operator==(const Base::iterator& rhs) const {
return base->vec[x][y] == *rhs;
}
bool Base::iterator::operator!=(const Base::iterator& rhs) const {
return base->vec[x][y] != *rhs;
}
// Bunch of other functions
Any help would be appreciated.
Base::iterator(this, vec.size()-1, vec[0].size()-1); this will return a valid last element. So you need to change it to Base::iterator(this, vec.size(), 0);, and also update the conditions to switch to a new row in your loop.
Something like:
// if iterator has not reached end
if(x < base->vec.size())
{
++y;
// if y has reached end of row, increment x and start y on a new row
if(y >= base->vec[0].size() {
y=0;
++x;
}
}
Also the iterators are wrong:
bool Base::iterator::operator==(const Base::iterator& rhs) const {
return base == rhs.base && x == rhs.x && y == ris.y;
}
bool Base::iterator::operator!=(const Base::iterator& rhs) const {
return !(base == rhs.base && x == rhs.x && y == ris.y);
}

Square bracket overloading operator to set instead of get c++

For getting the value(i.e the function returns the value)
for ex -
if we do this in main.cpp
cout << Object[0] << endl;
it will print the first element of the object array.
and the function will look like this
double myArray::operator[](int index) const {
*//your code*
}
but what if we need to set the value what would be the prototype going to look like?
Let's say in main.cpp, we have
object[0] = 5;
Now this should set the first element as 5 we know that it shouldn't return anything!! so return_type is void!! but how we going to pass the index(i.e 0) and the RHS(Right hand side) value into the function?
Just declare two operators
const double & myArray::operator[](int index) const {
*//your code*
}
and
double & myArray::operator[](int index) {
*//your code*
}

Assigning Private Variable within a constructor

I've read through stack overflow threads multiple times in the past, and they're often quite helpful. However, I've run into a problem that simply doesn't make sense to me, and I'm trying to figure out what I missed. Here's the sections of the code that I'm having trouble with:
class BigInts
{
public:
static const std::size_t MAXLEN = 100;
BigInts(signed int i); //constructor
BigInts(std::string &); //other constructor
std::size_t size() const;
digit_type operator[](std::size_t ) const;
private:
digit_type _data[MAXLEN];
bool _negative;
int _significant;
};
//nonmember functions
std::ostream & operator << (std::ostream &, const BigInts &);
BigInts::BigInts(signed int i)
{
_negative = (i < 0);
if (i < 0)
{
i = -1*i;
}
std::fill(_data, _data+MAXLEN, 0);
if (i != 0)
{
int d(0);
int c(0);
do
{
_data[d++] = ( i % 10);
i = i / 10;
c++; //digit counter
}while(i > 0);
//_significant = c; //The problem line
assert(c <= MAXLEN); //checks if int got too big
}
}
std::size_t BigInts::size() const
{
std::size_t pos(MAXLEN-1);
while (pos > 0 && _data[pos] == 0)
--pos;
return pos+1;
}
std::ostream & operator << (std::ostream & os, const BigInts & b)
{
for (int i = (b.size() - 1); i >= 0; --i)
os << b[i];
return os;
}
int main()
{
signed int a, b;
std::cout << "enter first number" << std::endl;
std::cin >> a;
std::cout << "enter second number" << std::endl;
std::cin >> b;
BigInts d(a), e(b), f(b);
std::cout << d << " " << e << " " << f;
Major edit, switched from an attempted dummy version of the code to the actual code I'm using, complete with the original variable names. I tried to remove anything that isn't relevant to the code I'm currently working with, but if you see a strange name or call in there, let me know and I can post the associated portion.
The code had been working fine prior to the introduction of _significant, which is a variable I had added to add some more functionality to the class as a whole. However, when I attempted to drive the basic parts of it using the main function you see displayed, it encountered large errors. For example, I inputted 200 and 100 for a and b respectively, it outputted 201, 1, and 3 for d, e, and f. As it currently stands, the ONLY place _significant appears is when I'm attempting to assign the value of c to it.
The only error I can see right now is that _significant isn't initialized when the input is zero.
Step through it in a debugger, make sure the the right digits are ending up in the array and that the array data isn't being overwritten unexpectedly.
EDIT: It works for me (cleaned up slightly). More cleaned up, also working: http://ideone.com/MDQF8
If your class is busted purely by assigning to a member variable, that means stack corruption without a doubt. Whilst I can't see the source offhand, you should replace all buffers with self-length-checking classes to verify accesses.
The line i - 1; in the original code looks highly suspicious. Did you want to write i -= 1; or --i; or something else?
It decrements i by 1 and then throws away the result.