I have created my own class like this:
template<class T>
class ball
{
T size;
T price;
};
Now I want to support comparing two balls only according to the first value size in this case should I implement all those operators for ball class??
==, !=, >=, <=, >, <
This doesn't sound efficient or correct.
Which operators should I implement in my class?
In general, at minimum you should implement those operators which you use. And the ones that are required by concepts that you need the class to fulfill.
If you want the class to be equality comparable, then ideal design is to also let the class be comparable using operator!= and if you want the class to be comparable with ordered relations, then ideal design is to let the class be comparable with all operators.
should I implement all those operators for ball class??
Pre-C++20: Yes, this is a good idea if you want the class to be comparable.
Since C++20: No, you should in most cases only implement operator<=>. Preferably as defaulted.
I want to support comparing two balls only according to the first value size
I recommend to not define the comparison operators to behave this way. It will be highly confusing to the users of your class as they will likely expect the price to affect the equality of the object.
If you need this kind of comparison for a specific use case, then I recommend using a custom comparison object instead.
Another solution is to implement a method supporting all cases. An advantage would be that you could choose the test dynamically at runtime :
// in .hpp
typedef enum { Equal, LessOrEqual, GreaterOrEqual, NotEqual, GreaterThan, LessThan } Comparator;
bool compare(ball & a, ball & b, Comparator c = Equal);
// in .cpp
bool compare(ball & a, ball & b, Comparator c) {
bool r;
switch(c) {
case GreaterOrEqual: case LessThan: r = a.size >= b.size; break;
case LessOrEqual: case GreaterThan: r = a.size <= b.size; break;
default: r = a.size == b.size; break;
}
return c >= NotEqual ? !r : r;
}
Related
I'm kinda new to OOP so this question feels a bit weird but I want to know what I should do in this case
Say I have a Tup4 class which just holds 4 doubles, and two classes Point4 and Vec4 that extend Tup4. Now, checking for equality in Tup4 is just comparing whether all 4 doubles in each tuple are (approximately) equal. This holds in both classes extending it. However, it makes no sense to define an equality function in Tup4, because then I would be able to check for equality between a Point and a Vector, which doesn't make much sense. So I can't define a virtual equals method in Tup4, so what can I do? The code is exactly the same in both cases, the only difference is the type of the function. So I want to know if I can avoid having two methods
bool equals(Point4 p);
bool equals(Vec4 v);
Where they both do the same but are defined in different classes
It looks like you already accepted an answer, but here's what I was going to
I propose without going down the template route:
Define an equality method in your Tup4 class, but leave it protected:
class Tup4
{
public:
double a, b, c, d;
protected:
bool EqualityCheck(const Tup4& other) const
{
return (a == other.a && b == other.b && c == other.c && d == other.d);
}
};
Then your Point4 and Vec4 classes can have overloaded equality operators that call the parent's method:
class Point4 : public Tup4
{
public:
bool operator==(const Point4& other) const
{
return EqualityCheck(other);
}
};
You can use templates for this.
It actually is not a good use OOP to shoehorn value-like types such as mathematical vectors and points into an object hierarchy. Object hierarchies mean using "reference semantics"; whereas, vectors, tuples, and points want to be values.
Look at, for example, how the C++ standard library implements complex numbers. It implements them as a class template parametrized on the number type you'd like to use e.g. float, double, etc. and then overloads the arithmetic operators to handle complex<T>.
How you would really implement a vector etc. class is similar.
Tup4 is a concept not a class. Vec4 snd Point4 satisfy that concept.
Most of Vec4 and Point4 are implemented as templates.
In the rare case you need to handle Tup4s in runtime polymophic way, don't use inheritance, use type erasure like std function. But you probably won't.
struct Tup4Data{
double v[4];
};
template<class D>
struct Tup4Impl:Tup4Data{
// common implementation details of Tup4
// D is derived class (Vec4 or Point4)
};
struct Vec4:Tup4Impl<Vec4>{
// extra stuff for Vec4
};
struct Point4:Tup4Impl<Point4>{
// extra stuff for Poimt4
};
Now, code that just wants to work on raw doubles and doesn't care can take Tup4Data. Tup4Impl uses the CRTP if you want to look it up; this provides static polymorphism.
Those that care if it is a vector or a point can take either one.
Those that wants to take both and behave differently can be template code, or type erase.
This last case -- type erase -- is harder, but in exchange you get massive improvements in every other case. And 99% of code bases don't even need to type erase.
I'm not even certain what kind of situation has code that wants to type erase here.
So just don't worry about it. (If you want to learn, look up example std function implementations).
You want the two types Point4 and Vector4 to be incompatible with each other, in the sense that they are different types. Now, as yourself what you need the Tuple4 for. Is it really important that Point4 is a Tuple4? In other words, is the Liskov Substitution Principle important there? My guess is that the answer is that Tuple4 is just a convenient baseclass for code reuse, not for OOP reasons.
If my assumption is correct, using a private baseclass would be a better choice. Since the base is private, it won't allow comparing Vector4 and Point4. For convenient code reuse, you can forward to the baseclass implementations:
class Point4: Tuple4 {
public:
bool operator==(Point4 const& rhs) const {
return static_cast<Tuple4 const&>(*this) == static_cast<Tuple4 const&>(rhs);
}
};
That said, consider using std::array as baseclass instead of writing your own.
In my program, I use many arma::uvecs, and check equality between them like this
#include <armadillo>
using Vec = typename arma::uvec;
Vec v1({0, 0});
Vec v2({0, 1});
bool are_equal = arma::all(v1 == v2);
as I couldn't find any better equality operator in the Armadillo docs. Now that works perfectly fine, but to save some space, and as an exercise in subclassing and operator overloading, I want to define the equality sign directly between the vectors like this:
class Vec : public arma::uvec {
friend bool operator==(const Collapsed& lhs, const Collapsed& rhs) {
return arma::all(lhs == rhs);
}
};
But sadly, I can't get it to work like that. I'm grateful about any hints!
Operator overloads do not need to be part of a class. I would suggest implementing your comparison operator as a free function like this:
bool operator==(const arma::uvec& lhs, const arma::uvec& rhs) {
return arma::all(lhs == rhs);
}
Regarding the friend in your question: As a quick summary, it provides the function that is befriended access to private and protected members of the class where the friend declaration is located. It it is not used to implement functions.
You can read more about it on cppreference or on this SO question
EDIT
Since the above only works if operator== is not already defined, here is a version that overrides it's implementation for a custom subclass:
class Vec : public arma::uvec
{
public:
bool operator==(const Vec& other)
{
// depending on wether arma implemets operator== as member or free function
// return arma::all(this->arma::uvec::operator==(other));
return arma::all(arma::operator==(*this, other));
}
};
Problem is library itself:
Armadillo: C++ library for linear algebra & scientific computing
operators: + − * % / == != <= >= < > && ||
Overloaded operators for Mat, Col, Row and Cube classes
Operations:
+ addition of two objects
− subtraction of one object from another or negation of an object
* matrix multiplication of two objects; not applicable to the Cube class unless multiplying by a scalar
% element-wise multiplication of two objects (Schur product)
/ element-wise division of an object by another object or a scalar
== element-wise equality evaluation of two objects; generates a matrix/cube of type umat/ucube
!= element-wise non-equality evaluation of two objects; generates a matrix/cube of type umat/ucube
and uvec is:
uvec = ucolvec = Col<uword>
so operator== is already there and its functionality is strange/unexpected.
My recommendation is: do not fight with a library. Do not try provide own operator. Just provide a named function areEqual.
Defining a class just to provide own equal operator is not a best choice and if doing that then IMO it is better to use composition not inheritance (depending on requirement it will be more boiler plate code in class itself, but it will be easier to avoid unexpected behaviors).
I'm a bit confused about using STL set::find() for a set of my own defined class objects.
My class contains more than two items (3/4/5 etc.), so how can I overload less operator?
I tried for 3 variable, which is as follows and working fine:
return( (a1.i < a2.i) ||
(!(a1.i > a2.i) && (a1.f < a2.f)) ||
(!(a1.i > a2.i) && !(a1.f > a2.f) && (a1.c < a2.c)));
where, a1, and a2 are class objects and (i, f and c are class members).
Now I want to generalize this for n members, but my find() does not always work.
I've been looking through STL's detailed documentation, trying to learn how set::find() is implemented, and why it needs less (<) operator overloading.
I referred to sgi and msdn documentation, but I could not find much about implementation details of set::find() there, either.
What am I doing wrong in my set::find() implementation?
You can use a tuple to easily get an lexicographical ordering of your members:
return std::tie(lhs.i, lhs.f, lhs.c) < std::tie(rhs.i, rhs.f, rhs.c);
This requires that every member be of a comparable type, e.g. lhs.i < rhs.i makes sense.
Note that std::tie and std::tuple are only available for C++11, so for C++03 you can use e.g. Boost.Tuple which does provide a boost::tie (boost::tuple uses the same ordering as std::tuple).
As to where this should go, it is customary to put that in an operator< (after all this is what make the use of tie for an easy ordering possible in the first place). Quite often this operator will be a friend, so this would look like:
class foo {
public:
/* public interface goes here */
// declaration of non-member friend operator
// if it doesn't need to be a friend, this declaration isn't needed
friend
bool operator<(foo const& lhs, foo const& rhs);
private:
T t;
U u;
V v;
};
bool operator<(foo const& lhs, foo const& rhs)
{
// could be boost::tie
return std::tie(lhs.t, lhs.u, lhs.v) < std::tie(rhs.t, rhs.u, rhs.v);
}
As you can see it's not fully automatic as the implementation of operator< needs to list every member of foo (or at least those that matter for the ordering), twice. There isn't a better way I'm afraid.
Instead of providing an operator< you can specialize std::less for foo but that's a bit exotic and not the preferred way. If the ordering would still not make sense to be part of the extended interface of foo (e.g. there might be more than one ordering that makes sense without a canonical one), then the preferred way is to write a functor:
struct foo_ordering {
bool operator()(foo const& lhs, foo const& rhs) const
{
/* implementation as before, but access control/friendship
has to be planned for just like for operator< */
}
};
Then you'd use e.g. std::set<foo, foo_ordering>.
Be aware that no matter what form the ordering takes (through either operator<, std::less<foo> or a functor) if it is used with an std::set or any other associative container (and by default e.g. std::set<T> uses std::less<T> which in turn uses operator< by default) it must follow some stringent criteria, i.e. it must be a strict weak ordering. However if all the members that are used for the foo ordering themselves have SW orderings then the resulting lexicographical ordering is also a SW ordering.
You have to define a strict ordering of your objects. So if your object is made up of n members a_1 .. a_n which all have a strict ordering themselves, what you can do is:
bool operator< (const TYPE &rhs) {
if (a_1 < rhs.a_1) return true; else if (a_1 > rhs.a_1) return false;
if (a_2 < rhs.a_2) return true; else if (a_2 > rhs.a_2) return false;
...
if (a_n < rhs.a_n) return true;
return false;
}
Edit:
If either boost or C++11 is an option for you, you should really go with the std::tie/boost::tie method Luc Danton suggests in his answer. It's much cleaner.
std::set element comparison function should define Strict Weak Ordering relation on elements domain. Using this definition we can say that two elements are equivalent if compare( a, b ) is false and compare( b, a ) is false too. std::find can be implemented using this assumption.
You can find more here: http://www.sgi.com/tech/stl/set.html and http://www.sgi.com/tech/stl/StrictWeakOrdering.html
Your operator < should be capable to compare every object with given one, like that
struct Data
{
bool operator < (const Data& right) const
{
return( (this.i < right.i) ||
(!(this.i > right.i) && (this.f < right.f)) ||
(!(this.i > right.i) && !(this.f > right.f) && (this.c < right.c)));
}
}
Also, your compare algorithm looks doubtful, because it doees not consider cases, when
this.i == right.i
or
this.f == right.f
And you actually should not be interested in std::set implementation. It can change from compiler to compiler and can be modified in future. Your program should make assumptions only about container interface, never implementation.
This is only a partial answer, but a detailed documentation of STL can be found on the website of SGI.
What is the difference between these two ways of overloading the != operator below. Which is consider better?
Class Test
{
...//
private:
int iTest
public:
BOOL operator==(const &Test test) const;
BOOL operator!=(const &Test test) const;
}
BOOL operator==(const &Test test) const
{
return (iTest == test.iTest);
}
//overload function 1
BOOL Test::operator!=(const &Test test) const
{
return !operator==(test);
}
//overload function 2
BOOL Test::operator!=(const &Test test) const
{
return (iTest != test.iTest);
}
I've just recently seen function 1's syntax for calling a sibling operator function and wonder if writing it that way provides any benefits.
Your first overload ensures that calling != on your type will always provide the opposite of calling == even if your implementation of == would change.
Your second overloaded function does not, since it is possible to provide any implementation for == and change the existing implementation in the future.
If you want to ensure that != will always be the opposite of ==, go with the first (at the cost of an extra function call which may very well become inlined anyway).
Here is a good example. Suppose that you have a class Point2D with fields x and y. If you want to implement ==, you will have to compare on field x and on field y. If you implement != by calling operator==, you have shorter code, and will have one function less to change if you ever moved to a polar representation.
Equality tests and comparisons are always susceptible to maintenance errors as the class fields change. Minimizing the number of methods that directly access state can reduce the risk of errors.
They will almost certainly compile to the same machine code.
I prefer choice 2, just because I find it awkward to say "operator==". But you could have used
return ! (*this == test)
And IMHO that's also clear and easy to understand.
I can think of many reasons (or perhaps aspects of the same reason) to write it that way. What they all boil down to is: it's DRY.
It ensures that two objects are always either == or !=
If you decide to change what's in the class, or what's used for equality testing, you only have to change it in one place
I think that conceptually, you really have two different things you're defining here:
A definition of "equality" for class Test
A useful interface by which people using this class can determine equality of their instances
With method 2, you're doing both ad-hoc. With method 1, you're defining equality in operator==, and providing the rest of the interface via operator!=.
Some languages/libraries take it even further, e.g., in Ruby you can define just <=> to compare ordered objects and mix-in Comparable and get equality, inequalities, and between?.
Version #1, while syntacticly ugly IMHO, allows you to change the equality logic in a single place (in the == operator overload). It guarantees the two overloads are always in sync.
In general, the following statement:
return !(*this == object);
allows you to define != in terms of one function. In the world of inheritance, child objects would only need to define operator== in order to use the base class operator!=:
struct Base
{
virtual bool isEqual(const Base& other) const = 0;
bool operator==(const Base& other) const
{
return isEqual(other);
}
bool operator!=(const Base& other) const
{
return !(*this == other); // Uses Base::operator==
}
};
With the above base class, defining operator!= using != would require descendants to implement more methods.
Also, !(*this == other) allows one to define a global, generic function for !=:
template <typename T>
bool operator!=(const T& a, const T& b)
{
return !(a == b);
}
Although this pattern doesn't provide much for == and !=, the differences are larger when using the relational operators: <, <=, >, >=.
In general, it is always better to implement related functionality in terms of each other. In case of operators, there are always groups. For example, != can be implemented in terms of ==; post-increment can be implemented in terms of pre-increment; >, <= and >= can be implemented in terms of < (see std::rel_ops in <utility>) etc. If something about the class needs changing, you only need to modify the core operators, and all the rest will automatically be updated to reflect the new behavior.
The general implementation of all the "secondary" operators is always the same, and so there is even a library which automatically provides operators that are defined in terms of a few provided ones. See Boost.Operators
Your example:
#include <boost/operators.hpp>
class Test : boost::equality_comparable<Test, Test>
{
private:
int iTest;
public:
bool operator==(const Test& test) const;
//look, no operator !=
};
int main()
{
Test a, b;
a != b; //still works
}
Let's say I have:
class myClass
std::list<myClass> myList
where myClass does not define the == operator and only consists of public fields.
In both VS2010 and VS2005 the following does not compile:
myClass myClassVal = myList.front();
std::find( myList.begin(), myList.end(), myClassVal )
complaining about lack of == operator.
I naively assumed it would do a value comparison of the myClass object's public members, but I am almost positive this is not correct.
I assume if I define a == operator or perhaps use a functor instead, it will solve the problem.
Alternatively, if my list was holding pointers instead of values, the comparison would work.
Is this right or should I be doing something else?
The compiler does not automatically generate a default operator==(), so if you don't write one yourself, objects of your class can't be compared for equality.
If you want memberwise comparison on the public members you have to implement that yourself as operator==() (or "manually" use a separate function/functor to do the comparison).
Find does require the value to be equality comparable, and the compiler will not define you a default operator==.
Alternatively, you can use find_if and supply a functor predicate.
std::find needs operator==. Even if the members are public, it doesn't necessarily mean that all of them are relevant in defining what equality means for this class.
If you don't want to overload the operator for some reason (e.g there is no one single intuitive meaning of equality for that class, instances could be consider equal in some respect or another), you can code a suitable function object and use std::find_if. For example:
struct same_surname_as
{
Person p;
same_surname_as(const Person& x): p(x) {}
bool operator()(const Person& person) const { return p.surname == person.surname; }
};
list<Person> li;
find(li.begin(), li.end(), same_surname_as(Person("Pu Songling"));