C++ operator overloading affect in-class operator functions - c++

What if i overload the != operator and use class!= inside one of other operator overloaders, does it accept it as non-overloaded or overloaded? I am trying to create a noob_ptr (a kind of custom-pointer wraper i am thinking of)
class noob_ptr
{
private: //does this change the behaviour? public? protected?
bool operator!=(noob_ptr x)
{
...
}
bool operator,(noob_ptr y)
{
...
if(y!=z)...
...
}
...
}
Does below example cancel usage of overloaded-operator in my class?
class noob_ptr
{
protected: //or public
bool operator,(noob_ptr y) //yes, z is also a noob_ptr
{
...
if(y!=z)...
...
}
...
private:
bool operator!=(noob_ptr x)
{
...
}
}

If type of z is also a noob_ptr, then the answer is YES, it will call the overloaded operator != for your class.
Also, I'd suggest you this comparison method signature:
bool operator != (const noob_ptr& x) const;
so it can be used for constant pointers and also avoid object copying while calling the overloaded operator.
UPD: If you declare operator != as private, then it'll be available in all member functions of noob_ptr class, friend classes and functions of noob_ptr class, and for all other usages will result in a compilation error with a message like: "operator != is inaccessible due to its protection level"

If the operands you supply are ones for which the language's built-in != will work, then that's what gets used. If they're of user-defined types, then it'll search for a user-defined operator!= that's defined for those types (or some types that support implicit conversion from those types).

C++ will always use the "best match" which is the closest in qualifiers, access specifiers such as private, scope, namespace, etc.
So, if there is a global namespace operator!= and a class one (that lacks the left-hand-side argument which is assumed to be the class& or const class& if the method is const -- which it should be), then inside the class (namespace) you will get the one inside the class.
If there is only one between the global namespace and the class, you will obviously get that one.
The following code demonstrates between global and class scope. You can extend this by adding const qualifiers, etc.
#include <iostream>
using namespace std;
// Forward declaration to use without the class definition
class X;
bool operator!=( int lhs, const X& rhs) {
cout << "bool operator!=( int lhs, const X& rhs)" << endl;
return false;
}
bool operator!=(const X& lhs, const X& rhs) {
cout << "bool operator!=(const X& lhs, const X& rhs)" << endl;
return false;
}
bool operator!=(const X& lhs, int rhs) {
cout << "bool operator!=(const X& lhs, int rhs)" << endl;
return false;
}
// Note: Can't do: bool operator!=(int lhs, int rhs) -- already defined
class X {
private:
int x;
public:
X(int value) : x(value) { }
bool operator !=(const X& rhs) {
cout << "bool X::operator !=(const X& rhs)" << endl;
return true;
}
bool operator !=(int rhs) {
cout << "bool X::operator !=(int rhs)" << endl;
return true;
}
void f() {
X compare(1);
cout << "X::f()" << endl;
cout << (5 != 3) << endl; // Uses built-in
cout << (*this != 3) << endl; // Uses member function
cout << (*this != 1) << endl; // Uses member function
cout << (1 != *this) << endl; // There can be no member function, uses global namespace
cout << (*this != compare) << endl;
}
};
void f(const X& arg) {
cout << "f()" << endl;
X compare(1);
cout << (5 != 3) << endl; // Uses built in
cout << (arg != 3) << endl; // Uses global namespace
cout << (arg != 1) << endl; // Uses global namespace
cout << (1 != arg) << endl; // Uses global namespace
cout << (arg != compare) << endl; // Uses global namespace
}
int main(int argc, char **argv) {
X x(1);
x.f();
f(x);
return 0;
}

Related

incorrect function call on overload operator

In the code, why is (10 != i) calling == instead of !=? The other two call !=
#include <iostream>
class Integer
{
int x;
public:
bool
operator== (const Integer &i)
{
std::cout << "==";
return x == i.x;
}
bool
operator!= (const Integer &i)
{
std::cout << "!=";
return x != i.x;
}
Integer (int t = 0) { x = t; }
};
int
main ()
{
Integer i;
std::cout << (i != i) << '\n'; // calls !=
std::cout << (i != 100) << '\n'; // calls !=
std::cout << (10 != i) << '\n'; // calls ==
}
Prior to C++20, you'd need to add two free functions for the comparison where the int is on the left-hand side:
bool operator==(int lhs, const Integer& rhs) {
return rhs == lhs;
}
bool operator!=(int lhs, const Integer& rhs) {
return rhs != lhs;
}
You should also make the member comparison operators const qualified:
class Integer {
public:
//...
bool operator==(const Integer &i) const { // note const
std::cout << "==";
return x == i.x;
}
bool operator!=(const Integer &i) const { // note const
std::cout << "!=";
return x != i.x;
}
//...
};
You could also remove the member operators to simplify things. Now the left-hand side int will be implicitly converted to Integer and then compared with the right-hand side:
class Integer {
int x;
public:
Integer(int t = 0) : x{t} {}
friend bool operator==(const Integer& lhs, const Integer& rhs) {
return rhs.x == lhs.x;
}
friend bool operator!=(const Integer& lhs, const Integer& rhs) {
return !(rhs == lhs);
}
};
Since you've tagged this C++20, you can let operator== do all the work. See Default comparisons. It'll be used for operator!= too.
class Integer {
int x;
public:
bool operator==(const Integer &i) const {
std::cout << "==";
return x == i.x;
}
Integer(int t = 0) : x{t} {}
};
... and it'll correctly show that it used operator== for all your != comparisons (and negated it).
More from Defaulted equality comparison:
A class can define operator== as defaulted, with a return value of bool. This will generate an equality comparison of each base class and member subobject, in their declaration order. Two objects are equal if the values of their base classes and members are equal. The test will short-circuit if an inequality is found in members or base classes earlier in declaration order.
Per the rules for operator==, this will also allow inequality testing
This means that you will in fact get away with the below only since C++20:
class Integer {
int x;
public:
bool operator==(const Integer &i) const = default;
Integer(int t = 0) : x{t} {}
};
or even better, get all the comparison operators for free by defaulting the spaceship operator <=>:
class Integer {
int x;
public:
auto operator<=>(const Integer &i) const = default;
Integer(int t = 0) : x{t} {}
};
There are two new additions to C++20 that made this possible (note that your code doesn't compile in earlier standard versions).
Compiler will attempt to replace a != b with !(a == b) if there is no suitable != for these arguments.
If there is no suitable a == b, compiler will attempt b == a as well.
So, what happens - compiler first notices that it doesn't know how to compare 10 != i, so it tries !(10 == i). There is still no suitable comparison, so it tries !(i == 10) and it can finally be done using your implicit constructor to convert 10 to Integer.
It can be easily verified by adding more info to debug print:
bool
operator== (const Integer &i) const
{
std::cout << x << "==" << i.x << ' ';
return x == i.x;
}
will print 0==10 1 in the last line (see it online).
As noticed in comments, you don't even need operator !=, due to aforementioned behaviour C++20 compiler will automatically convert any such call to operator ==.

Problems with ostream

I'm working in a Big Integer implementation in C++ and I'm trying to use cout with my BigInt class. I already overloaded the << operator but it doesn't work in some cases.
Here is my code:
inline std::ostream& operator << (ostream &stream, BigInt &B){
if (!B.getSign()){
stream << '-';
}
stream << B.getNumber();
return stream;
}
The code above works with:
c = a + b;
cout << c << endl;
But fails with:
cout << a + b << endl;
In the first case the program runs fine, but in the second the compiler gave an error:
main.cc: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
It's possible to overload the << operator for function in both cases?
Methods:
string getNumber ();
bool getSign ();
string BigInt::getNumber (){
return this->number;
}
bool BigInt::getSign (){
return this->sign;
}
As chris already pointed out in comments very quickly (as usual), you have a temporary created in here:
cout << a + b << endl;
You cannot bind that to a non-const reference. You will need to change the signature of your operator overloading by adding the const keyword to the reference.
This code works for me with a dummy BigInt implementation (as you have not shared yours):
#include <iostream>
using namespace std;
class BigInt
{
public:
bool getSign() const { return true; }
int getNumber() const { return 0; }
const BigInt operator+(const BigInt &other) const {}
};
inline std::ostream& operator << (ostream &stream, const BigInt &B){
// ^^^^^
if (!B.getSign()){
stream << '-';
}
stream << B.getNumber();
return stream;
}
int main()
{
BigInt a, b, c;
c = a + b;
cout << c << endl;
cout << a + b << endl;
return 0;
}
But yeah, I agree that the error message is not self-explanatory in this particular case.
Change
inline std::ostream& operator << (ostream &stream, BigInt &B){
to
inline std::ostream& operator << (ostream &stream, BigInt const& B){
c can be a used where BiInt& is expected but a+b cannot be because a+b is a temporary. But it can be used where BigInt const& is expected.

Do I have to overload every operator for a class to behave like one of its member variables?

Given a user defined type such as the following:
struct Word{
std::string word;
Widget widget;
};
Is there a way to make every overloaded operator of the class behave exactly the same as if it was just a string? Or do I have to implement the class the following way:
struct Word{
bool operator < (Word const& lhs) const;
bool operator > (Word const& lhs) const;
bool operator <= (Word const& lhs) const;
bool operator => (Word const& lhs) const;
bool operator == (Word const& lhs) const;
bool operator != (Word const& lhs) const;
//etc...
std::string word;
Widget widget;
};
making sure I account for every overloaded operation a string contains, and applying the behaviour to just the string value.
I would say your best option is to use std::rel_ops that way you only have to implement == and < and you get the functionality of all of them. Here's a simple example from cppreference.
#include <iostream>
#include <utility>
struct Foo {
int n;
};
bool operator==(const Foo& lhs, const Foo& rhs)
{
return lhs.n == rhs.n;
}
bool operator<(const Foo& lhs, const Foo& rhs)
{
return lhs.n < rhs.n;
}
int main()
{
Foo f1 = {1};
Foo f2 = {2};
using namespace std::rel_ops;
std::cout << std::boolalpha;
std::cout << "not equal? : " << (f1 != f2) << '\n';
std::cout << "greater? : " << (f1 > f2) << '\n';
std::cout << "less equal? : " << (f1 <= f2) << '\n';
std::cout << "greater equal? : " << (f1 >= f2) << '\n';
}
If you need a more complete version of this type of thing use <boost/operators.hpp>

define both operator void* and operator bool

I tried creating a class with one operator bool and one operator void*, but the compiler says they are ambigous. Is there some way I can explain to the compiler what operator to use or can I not have them both?
class A {
public:
operator void*(){
cout << "operator void* is called" << endl;
return 0;
}
operator bool(){
cout << "operator bool is called" << endl;
return true;
}
};
int main()
{
A a1, a2;
if (a1 == a2){
cout << "hello";
}
}
The problem here is that you're defining operator bool but from the sounds of it what you want is operator ==. Alternatively, you can explicitly cast to void * like this:
if ((void *)a1 == (void *)a2) {
// ...
}
... but that's really bizarre. Don't do that. Instead, define your operator == like this inside class A:
bool operator==(const A& other) const {
return /* whatever */;
}
You could call the operator directly.
int main()
{
A a1, a2;
if (static_cast<bool>(a1) == static_cast<bool>(a2)){
cout << "hello";
}
}
In this case, though, it looks like you should define operator==() and not depend on conversions.

Why doesn't my overloaded comma operator get called?

I'm trying to overload the comma operator with a non-friend non-member function like this:
#include <iostream>
using std::cout;
using std::endl;
class comma_op
{
int val;
public:
void operator,(const float &rhs)
{
cout << this->val << ", " << rhs << endl;
}
};
void operator,(const float &lhs, const comma_op &rhs)
{
cout << "Reached!\n"; // this gets printed though
rhs, lhs; // reversing this leads to a infinite recursion ;)
}
int main()
{
comma_op obj;
12.5f, obj;
return 0;
}
Basically, I'm trying to get the comma operator usable from both sides, with a float. Having a member function only allows me to write obj, float_val, while having an additional helper non-friend non-member function allows me to write float_val, obj; but the member operator function doesn't get called.
GCC cries:
comma.cpp: In function ‘void operator,(const float&, const comma_op&)’:
comma.cpp:19: warning: left-hand operand of comma has no effect
comma.cpp:19: warning: right-hand operand of comma has no effect
Note:
I realise that overloading operators, that too to overload comma op., Is confusing and is not at all advisable from a purist's viewpoint. I'm just learning C++ nuances here.
void operator,(const float &rhs)
You need a const here.
void operator,(const float &rhs) const {
cout << this->val << ", " << rhs << endl;
}
The reason is because
rhs, lhs
will call
rhs.operator,(lhs)
Since rhs is a const comma_op&, the method must be a const method. But you only provide a non-const operator,, so the default definition will be used.