Right way to overload < operator? - c++

I have a class called user which has a lname field. Is this the right way to overload the "<" operator?
bool User::operator<(const User& other)
{
std::cout << "< operator was called" << std::endl;
if (this != &other)
{
if (lname.compare(other.lname) == 0)
{
return true;
}
}
return false;
}
I am trying to use this in a more complicated set of things and it is failing - just want to make sure this much is right.

As others have pointed out, your operator< doesn't allow the left side to be const. Changing the function signature to
bool User::operator<(const User& other) const
is an improvement. But I would actually recommend making it a non-member function instead:
class User {
public:
friend bool operator<(const User& u1, const User& u2);
// ...
};
bool operator<(const User& u1, const User& u2)
{
// ...
}
For one thing, it's a little more legible in my opinion.
But also, it sometimes makes a technical difference. With a non-member function, the expression a < b attempts implicit conversions on both a and b to see if your operator< is a viable overload. But with a member function, implicit conversions can apply to b, but not to a: a must be of type User or a derived type. This can lead to surprising situations where a < b compiles but b < a doesn't.

It seems better to me to hide the 'lname' field as private.
return lname.compare(other.getName()) < 0;

Try:
bool User::operator<(const User& other) const
{
return lname.compare(other.lname) < 0;
}

The correct way to implement operator< is as a const-function:
bool User::operator<( const User& other ) const
This means that the function does not modify its members and thus can be called on const instances of your class.

Related

Can I compare 2 structures in C++?

I have simply declared a structure like this -
struct data{
int x,y;
};
Now I have declared 2 variables a & b of data type. I've assigned appropriate values to them. Now, I want to check if they are equal! I am trying to do like this -
data a,b;
a.x=12, a.y=24;
b.x=15, b.y=30;
if(a!=b)cout<<"a~b"<<endl;
But the compiler is giving me the following error on the 4th line ->
error: no match for 'operator!=' (operand types are 'data' and 'data')
Where is the problem actually? Isn't this compare supported in C++?? Or I'm making any mistakes??
What is the exact and easiest way to do this?? Do I need to compare each of the elements in the structure separately?? Or there's any other smarter way??
C++ gives you attribute-by-attribute assignment implicitly, but no comparison for equality or ordering. The reason is "just because", don't look too hard into philosophy.
You must to provide those operators, if needed, by implementing them yourself explicitly, for example:
bool operator<(const Data& other) const {
if (x < other.x) return true;
if (x > other.x) return false;
return y < other.y;
}
bool operator==(const Data& other) const {
return x == other.x && y == other.y;
}
and so on.
Note also that defining for example == doesn't give you != automatically and defining < doesn't provide >= implicitly.
UPDATE
C++20 introduces (will introduce) a new operator <=> (friendly name "spaceship operator") exactly to remove the verbosity of having to define all possible relational operators. In this case adding:
std::strong_ordering operator<=>(const Data& other) const {
if (auto cmp = x <=> other.x; cmp != 0) return cmp;
return y <=> other.y;
}
will allow compilation of all relational tests (<, <=, >, >=, ==, !=) between elements of the class based on checking x first and, if that check doesn't resolve, checking y instead.
You have to implement all operators explicitely that you intent to use. In your case, you will need to supply bool operator!=(const data&, const data&).
A nice way to implement it for PODs like this is to use std::tuple since it already implements ordering:
#include <tuple>
// ...
bool operator!=(const data& p_lhs, const data& p_rhs)
{
return std::tie(p_lhs.x, p_lhs.y) != std::tie(p_rhs.x, p_rhs.y);
}
std::tie (documentation) creates a temporary tuple of references. Those two tuples can then be compared, since std::tuple defines all comparison operators, as shown here.
I chose to implement operator!= as a free function. You can, of course, choose to implement it as member of your class:
struct data
{
bool operator!=(const data& p_rhs) const
{
return std::tie(x, y) != std::tie(p_rhs.x, p_rhs.y);
}
int x, y;
};
Of course you should define all other operators, too. Remember that you can implement most operators by delegating to others.
Automatic C++ comparisons are coming in C++20, so you can just add a special operator to indicate that you need default comparisons when new standard is out.
class Point {
int x;
int y;
public:
auto operator<=>(const Point&) const = default;
// ... non-comparison functions ...
};
https://en.cppreference.com/w/cpp/language/default_comparisons
You have to implement bool operator != (const data&, const data&);.
Possible implementation (in c++11):
#include <tuple>
//...
bool operator == (const data& lhs, const data& rhs) {
return std::tie(lhs.x, lhs.y) == std::tie(rhs.x, rhs.y);
}
bool operator != (const data& lhs, const data& rhs) {
return !(lhs == rhs);
}

c++ less operator overload, which way to use?

For example: in a C++ header file, if I defined a struct Record and I would like to use it for possible sorting so that I want to overload the less operator. Here are three ways I noticed in various code. I roughly noticed that: if I'm going to put Record into a std::set, map, priority_queue, … containers, the version 2 works (probably version 3 as well); if I'm going to save Record into a vector<Record> v and then call make_heap(v.begin(), v.end()) etc.. then only version 1 works.
struct Record
{
char c;
int num;
//version 1
bool operator <(const Record& rhs)
{
return this->num>rhs.num;
}
//version 2
friend bool operator <(const Record& lhs, const Record& rhs) //friend claim has to be here
{
return lhs->num>rhs->num;
}
};
in the same header file for example:
//version 3
inline bool operator <(const Record& lhs, const Record& rhs)
{
return lhs->num>rhs->num;
}
Basically, I would like to throw the questions here to see if someone could come up with some summary what's the differences among these three methods and what are the right places for each version?
They are essentially the same, other than the first being non-const and allowing you to modify itself.
I prefer the second for 2 reasons:
It doesn't have to be a friend.
lhs does not have to be a Record
The best way to define the less operator is:
struct Record{
(...)
const bool operator < ( const Record &r ) const{
return ( num < r.num );
}
};
Welcome to c++20 where we have even more options.
//version 1
bool operator <(const Record& rhs)
{
return this->num>rhs.num;
}
this one is wrong, it should read:
//version 1
bool operator <(const Record& rhs)const
{
return this->num>rhs.num;
}
as you want the left hand side to be const-qualified as well.
//version 2
friend bool operator <(const Record& lhs, const Record& rhs) //friend claim has to be here
{
return lhs->num>rhs->num;
}
this one is symmetric. So suppose you have a struct Bar with an operator Record.
Then
Record rhs;
Bar lhs;
assert( lhs < bar );
the above works with a symmetric case, but not with a member function version.
The friend in class version is an operator that can only be found via Koenig lookup (Argument Dependent Lookup). This makes it very useful for when you want a symmetric operator (or one where the type is on the right, like ostream&<<*this) bound to a specific template class instance.
If it is outside of the class, it has to be template function, and a template function does overloading differently than a non-template function does; non-template functions permit conversion.
template<class T>
struct point {
T x ,y;
point operator-(point const& rhs)const{
return {x-rhs.x,y-rhs.y};
}
friend point operator+(point const& lhs, point const& rhs) {
return {lhs.x+rhs.x, lhs.y+rhs.y};
}
};
template<class T>
point<T> operator*( point<T> const& lhs, point<T> const& rhs ) {
return {lhs.x*rhs.x, lhs.y*rhs.y};
}
here - is asymmetric, so if we have a type that converts to a point<int> on the left, - won't be found.
+ is symmetric and a "Koenig operator", so it is a non-template operator.
* is symmetric, but is a template operator. If you have something that converts-to-point, it won't find the * overload, because deduction will fail.
//version 3
inline bool operator <(const Record& lhs, const Record& rhs)
{
return lhs->num>rhs->num;
}
this is similar to the template above, but here that problem doesn't occur. The difference here is that you can get the address of this function outside of the class, while the "koenig operator<" you wrote can only be found via ADL. Oh, and this isn't a friend.
c++17 adds in
auto operator<=>(const Record&)=default;
where we use the spaceship operator <=> to define ordering automatically.
This will use the ordering of both c and num to produce the required result.
Much like the rule of 5, you should seek to make =default here work correctly. Having state that < ignores is a bad smell, and so is entangling different parts of your state.
The non-member equivalent of your member function
bool operator <(const Record& rhs);
is
bool operator <(Record& lhs, const Record& rhs); // lhs is non-const
Now STL containers treat the items they store as const (at least as long as the comparison operator is concerned). So they call const-const variant of your operator. If they don't find it (in case you provided variant 1 only) - it is a compile error.
If you provide both const-const member and const-const non-member:
struct Record
{
bool operator <(const Record& rhs) const;
};
bool operator <(Record& lhs, const Record& rhs);
it is yet another compiler error because such definition leads to an ambiguity:
If two matches are found at the highest level where a match is found,
the call is rejected as ambiguous. /Stroustrup, C++, section 12.3.1/
Finally, (as noted in the previous answers) there's no need in the friend modifier since by default all fields of the struct are public.
PS make_heap doesn't expect the compared items to be const because it is a more low-level beast and using it you're kind of co-authoring a new heap-based library so it is your responsibility to track const-ness of items.
PPS set treatment of items as const does not protect you from modifying the keys of the items after they are inserted into the container - it will result in a runtime error (segfault) if you try it.
Favor in-class unless it cannot be in-class because first argument is the wrong type.

C++: Using base class's private members in equality test

I would like the following to compile, but it does not:
template <typename T>
struct Odp
{
public:
operator*() const
{
return m_p;
}
T* operator->() const
{
return m_p;
}
T** operator&()
{
return &m_p;
}
private:
T* m_p;
};
struct Ftw : public Odp<int>
{
bool operator==(const Ftw& rhs)
{
return m_p == rhs.m_p; // C2248 cannot access private member
}
};
Is there any way to make this work? I can't modify Odp.
Odp overloads operator* to return m_p. You can invoke the operator on *this and rhs:
struct Ftw : public Odp<int>
{
bool operator==(const Ftw& rhs) const
{
return **this == *rhs;
}
};
The operator* overload is a bit unusual, however: it should probably return *m_p instead, since operator-> returns m_p (this would result in your class having consistent pointer-like semantics). If you did this, you would then have to do the following to do the comparison:
return &**this == &*rhs; // or explicitly as:
return &this->operator*() == &rhs.operator*();
This is getting a bit messy, and it won't necessarily work if the unary & is overloaded for T (but, you really, really shouldn't do that...). You can also obtain the pointer by explicitly calling operator->, which might be preferable:
return this->operator->() == rhs.operator->();
The real question is, "what is this Odp, why are you using it, and why can you not modify it?"
On an unrelated note, your operator== should either be implemented as a const member function or, preferably, as a friend function:
bool operator==(const Ftw& rhs) const { /* ... */ }
friend bool operator==(const Ftw& lhs, const Ftw& rhs) { /* ... */ }
On another unrelated note, overloading the unary & is almost certainly a bad idea.
The compiler is telling you that m_p is private. If you want to access m_p in the derived class you need to make it either protected or public.
Since Odp is giving the pointer out for free in its methods (even the address of it, OMG! it's like making door with many locks and then giving the keys to every thief around), you can just do
bool operator==(const Ftw& rhs)
{
return **this == *rhs;
}
Had Odp implemented its own comparison operator, you could use it like this:
bool operator==(const Ftw& rhs)
{
return Odp<int>::operator==(rhs) && ... other conditions ...;
}
If you can't modify Odp, you can call operator->() explicitly. It returns what you need and should get inlined.

Overloading = in C++

I'm trying to overload the assignment operator and would like to clear a few things up if that's ok.
I have a non member function, bool operator==( const MyClass& obj1, const myClass& obj2 ) defined oustide of my class.
I can't get at any of my private members for obvious reasons.
So what I think I need to do is to overload the assignment operator. And make assignments in the non member function.
With that said, I think I need to do the following:
use my functions and copy information using strcpy or strdup. I used strcpy.
go to the assignment operator, bool MyClass::operator=( const MyClass& obj1 );
Now we go to the function overloading (==) and assign obj2 to obj1.
I don't have a copy constructor, so I'm stuck with these:
class Class
{
private:
m_1;
m_2;
public:
..
};
void Class::Func1(char buff[]) const
{
strcpy( buff, m_1 );
return;
}
void Class::Func2(char buff[]) const
{
strcpy( buff, m_2 );
return;
}
bool Class& Class::operator=(const Class& obj)
{
if ( this != &obj ) // check for self assignment.
{
strcpy( m_1, obj.m_1 );
// do this for all other private members.
}
return *this;
}
bool operator== (const Class& obj1, const Class& obj2)
{
Class MyClass1, MyClass2;
MyClass1 = obj1;
MyClass2 = obj2;
MyClass2 = MyClass1;
// did this change anything?
// Microsofts debugger can not get this far.
return true;
}
So as you can probably tell, I'm completely lost in this overloading. Any tips? I do have a completed version overloading the same operator, only with ::, so my private members won't lose scope. I return my assignments as true and it works in main. Which is the example that I have in my book.
Will overloading the assignment operator and then preforming conversions in the operator== non member function work? Will I then be able to assign objects to each other in main after having completed that step?
You have a couple of obvious mistakes here and there is some confusion about what you are actually trying to achieve. Firstly, the assignment operator operator = is meant to copy the value from one instance to another. The return value of the assignment operator is almost always a non constant reference to the target of the copy, so that you can chain assignments:
Class & operator=(const Class &rhs)
{
// copy the members
return *this;
}
The comparison operator operator == is meant to perform a comparison of two instances. It returns a boolean true if they are equal:
boolean operator==(const Class &rhs) const
{
// check if they are equal
return something;
}
The confusion is why are you trying to copy values around, or maybe assign to the instances in the comparison operator?
Op== isn't the assignment operator. T& Op= (const T&) is.
bool operator==(const T& lhs, const T& rhs) is the operation to compare two Ts. It returns true if lhs is equal to rhs, for whatever definition of "equal" you want to code.
I am guessing that you want to compare the two objects. In that case, you can just overload the operator == in class "Class". You don't need assignment operator.
class Class
{
public:
Class(int i) : m_i(i){}
bool operator==( const Class& rhs)
{
return m_i == rhs.m_i;
}
private:
int m_i;
};
int main()
{
Class t1(10), t2(10);
bool b = (t1 == t2);
}
I am not sure whether I understood the question correctly. But if you trying to check the equality using a non-member function and can't do this only because you can't access the private members of the class, then you can declare the non-member function as a friend function and use it like this:
class Test
{
public:
Test(int i) : m_i(i){}
private:
int m_i;
friend bool operator==(Test& first, Test& second);
};
bool operator==(Test& first, Test& second)
{
return first.m_i == second.m_i;
}
int main()
{
Test t1(10), t2(10);
bool b = (t1 == t2);
}

Quick and dirty operator!=

In my classes I often write a quick operator!= by returning !(*this == rhs), e.g.:
class Foo
{
private:
int n_;
std::string str_;
public:
...
bool operator==(const Foo& rhs) const
{
return n_ == rhs.n_ && str_ == rhs.str_;
}
bool operator!=(const Foo& rhs) const
{
return !(*this == rhs);
}
};
I can't see any obvious problems with doing this but thought I'd ask if anyone knows of any.
I believe that's the preferred method of implementing operator!= so that you don't repeat yourself, and you have a guaranteed correct relationship with operator==.
Defining operator!= as !operator== is just fine
For getting these trivial equivalent operators easily defined, I always use Boost.Operators.
The case with only operator== and operator!= (i.e. using equality_comparable<>) doesn't gain very much.
But when you need less and greater than too, or some combination of operator+, operator* etc. this becomes very convenient.
An example for your case would read
class Foo : private boost::equality_comparable< Foo >
{
private:
int n_;
std::string str_;
public:
...
bool operator==(const Foo& rhs) const
{
return n_ == rhs.n_ && str_ == rhs.str_;
}
};
No, that's absolutely fine - I do exactly the same.