Use of operator overloading in structure within class - c++

I have a header file where i am declaring a class with a structure within it. Also i am declaring an overloading operator(!=, to compare structures) as member of this class. I am giving the definition of this operator in the cpp file. But i am not able to access the members of the structure
car.h
class car
{
int carsor;
struct model
{
int id;
int mode;
}prev,curr;
bool operator !=(const model& model1);
};
car.cpp
#include "car.h"
bool car::operator !=(const model& model1)
{
if((model1.id==model.id)&&(model1.mode==model.mode))
{
return false;
}
else
{
return false;
}
}
The error i get is this
Error 2 error C2275: 'car::model' : illegal use of this type as an expression
how should i access the the structure members?

if((model1.id==model.id)&&(model1.mode==model.mode)) - model is the name of your class and not your object. Your object is accessible via this or you may omit it altogether inside the class.
Use if((model1.id==prev.id)&&(model1.mode==prev.mode)) to compare with prev or if((model1.id==next.id)&&(model1.mode==next.mode)) to compare with next.

This:
bool car::operator !=(const model& model1)
{
is a method comparing a car to a model. This, however:
bool car::model::operator != (car::model const &other) const
{
return !(*this == other);
}
is a method comparing two models (I've written it here as a method of car::model, but it could be a free function if you prefer.
I've also written it in terms of operator==, because the logic almost always works out easier:
bool car::model::operator ==(car::model const &other) const
{
return (this->id == other.id) && (this->mode == other.mode);
}
These methods would be declared as:
class car
{
struct model
{
int id;
int mode;
bool operator==(model const&) const;
bool operator!=(model const&) const;
// ...

Related

How to overload polymorphic == and != operator in c++

class Media {
public:
bool operator==(const Media& other) const {}
bool operator!=(const Media& other) const {}
};
class Book : public Media {
public:
bool operator==(const Book& other) const {} // commenting out this line solves this issue.
bool operator!=(const Book& other) const {}
};
class Game : public Media {
public:
bool operator==(const Game& other) const {}
bool operator!=(const Game& other) const {}
};
int main() {
Book book;
Game game;
bool res = book == game; // doesn't compile.
}
I have these 3 classes and they must have their own == and != operators defined. But then I also have to compare between two siblings using those operators.
I could've written a (pure) virtual function, say, virtual bool equals(const Media& other) const in the base class that subclasses override. And then call that function in the bodies of == and != opertor definition in base class Media. But that feature is gone when I add another bool operator==(const Book& other) const {} in the Book class (the same goes for the Game class too).
Now I want to compare between siblings using those operators and still have all 6 definition in those 3 classes. How do I make it work?
You mentioned in the comments that this form of comparison is an imposed restriction (to compare among siblings of a child type). If its an imposed restriction that you need to somehow perform this with inheritance, then one option is to fulfill the base signature and use dynamic_cast. Note that this is not a clean approach, but it might be the expected solution for this problem if this is some form of assignment.
dynamic_cast uses Runtime Type Information (RTTI) to determine whether an instance to a base class is actually an instance of the derived class. When you use it with a pointer argument, it returns nullptr on failure -- which is easily testable:
auto p = dynamic_cast<const Book*>(&other);
if (p == nullptr) { // other is not a book
return false;
}
// compare books
You can use this along with a virtual function to satisfy the hierarchy. However, to avoid possible ambiguities with c++20's generated symmetric operator==/operator!= functions, it's usually better to do this through a named virtual function rather than the operator== itself in order to prevent ambiguity:
class Media {
public:
virtual ~Media() = default;
bool operator==(const Media& other) const { return do_equals(other); }
private:
virtual bool do_equals(const Media& other) const = 0;
};
class Book : public Media {
...
private:
bool do_equals(const Media& other) const override {
auto* p = dynamic_cast<const Book*>(&other);
if (p == nullptr) { return false; }
return (... some comparison logic ...);
}
...
};
... Same with Game ...
Since we never define operator==(const Book&) or operator==(const Game&), we won't see this shadow the base-class' operator==; instead it always dispatches through the base's operator==(const Media&) -- which is non-virtual and prevents ambiguity.
This would allow a Book and a Game to be comparable, but to return false -- whereas two Book or two Game objects may be compared with the appropriate logic.
Live Example
That said...
This approach is not a good design, as far as software architecture goes. It requires the derived class to query what the type is -- and usually by the time you need to do this, that's an indication that the logic is funky. And when it comes to equality operators, it also leads to complications with symmetry -- where a different derived class may choose to compare things weirdly with different types (imagine a Media that may compare true with other different media; at which point, the order matters for the function call).
A better approach in general is to define each of the respective equality operators between any types that logically require equality comparison. If you are in C++20 this is simple with symmetric equality generation; but pre-C++20 is a bit of a pain.
If a Book is meant to be comparable to a Game, then define operator==(const Game&) or operator==(const Book&, const Game&). Yes, this may mean you have a large number of operator==s to define for each of them; but its much more coherent, and can get better symmetry (especially with C++20's symmetric equality):
bool operator==(const Game&, const Book&);
bool operator==(const Book&, const Game&); // Generated in C++20
bool operator==(const Game&, const Game&);
bool operator==(const Book&, const Book&);
In an organization like this, Media may not even be logical as a 'Base class'. It may be more reasonable to consider some form of static polymorphism instead, such as using std::variant -- which is touched on in #Jarod42's answer. This would allow the types to be homogeneously stored and compared, but without requiring casting from the base to the derived type:
// no inheritance:
class Book { ... };
class Game { ... };
struct EqualityVisitor {
// Compare media of the same type
template <typename T>
bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; }
// Don't compare different media
template <typename T, typename U>
bool operator()(const T&, const U&) const { return false; }
};
class Media
{
public:
...
bool operator==(const Media& other) const {
return std::visit(EqualityVisitor{}, m_media, other.m_media);
}
private:
std::variant<Book, Game> m_media;
};
Live Example
This would be my recommended approach, provided the forms of media are meant to be fixed and not extended.
You might do double dispatch thanks to std::visit/std::variant (C++17):
class Media;
class Book;
class Game;
using MediaPtrVariant = std::variant<const Media*, const Book*, const Game*>;
class Media {
public:
virtual ~Media () = default;
virtual MediaPtrVariant asVariant() const { return this; }
};
class Book : public Media {
public:
MediaPtrVariant asVariant() const override { return this; }
};
class Game : public Media {
public:
MediaPtrVariant asVariant() const override { return this; }
};
struct EqualVisitor
{
template <typename T>
bool operator()(const T*, const T*) const { return true; }
template <typename T, typename U>
bool operator()(const T*, const U*) const { return false; }
};
bool operator ==(const Media& lhs, const Media& rhs)
{
return std::visit(EqualVisitor(), lhs.AsVariant(), rhs.AsVariant());
}
bool operator !=(const Media& lhs, const Media& rhs)
{
return !(lhs == rhs);
}
int main()
{
Book book;
Game game;
bool res = book == game;
}
Demo

Is it OK to overload operators inside the header file (when declaring the class)?

Test.h:
class Test {
private:
int value;
public:
Test();
int getValue();
void setValue(int value);
bool operator >(Test &l) {
if (value > l.value) {
return true;
}
return false;
}
};
Can this cause any problems? If yes, what is the right way to implement it into a cpp file? If I attempt to implement it into a cpp file, I get an error saying that the number of arguments (because the function is now not inside the class?).
I'd say for such trivial functions this is the ideal way to do it because it allows the compiler to inline them, removing the function overhead.
But you should make the functions const where possible.
So:
class Test {
private:
int value;
public:
Test();
int getValue();
void setValue(int value);
bool operator >(const Test &l) const { // be const correct!
if (value > l.value) {
return true;
}
return false;
}
};
The function does not modify the data members at all so I have marked it const. Also the parameter is not changed so that too I have marked const.
If you do want to implement it into a separate cpp file then you need to qualify it with the class name:
Test.h
class Test {
private:
int value;
public:
Test();
int getValue();
void setValue(int value);
bool operator >(const Test &l) const; // declare only
};
Test.cpp
// Qualify the name with Test::
bool Test::operator >(const Test &l) const { // be const correct!
if (value > l.value) {
return true;
}
return false;
}
Also you can be a little more succinct with these functions:
// Qualify the name with Test::
bool Test::operator >(const Test &l) const { // be const correct!
return value > l.value;
}
In theory you should be making class objects as small as possible, and be doing everything you can in small related non-member functions. The difference I suspect you're getting bitten by is that a non-static member function defined inside a class always has an 'invisible' first/last parameter (the this pointer). You may forget that, but the compiler won't...

Overloading comparison operators

I'm having trouble overloading the comparison operators > and <. I've tried two different ways but I'm still having trouble.
bool Car::operator ==(const Car &car)
{
return mLNumber == car.GetNum();
}
bool Car::operator <(const Car &carB)
{
return mLNumber < carB.GetNum();
}
bool Car::operator >(const Car &carB)
{
return mLNumber > carB.GetNum();
}
int Car::GetNum()
{
return mLNumber;
}
My == operator works just fine. I get the error that these operators don't exist. Here is my 2nd attempt.
bool Car::operator <(const Car &carA, const Car &carB)
{
return carA.GetNum() < carB.GetNum();
}
bool Car::operator >(const Car &carB)
{
return carA.GetNum() > carB.GetNum();
}
And I get the error that there are too many parameters. I also get this:
'Car::GetNum' : cannot convert 'this' pointer from 'const Car' to 'Car &'
Try making your operators const:
bool Car::operator <(const Car &carB) const {
return mLNumber < carB.GetNum();
}
bool Car::operator >(const Car &carB) const {
return mLNumber > carB.GetNum();
}
Edit: And in this case, you should make the GetNum() function as const too because you are calling it on const Car& objects.
You don't need GetNum() either, you could just write
bool Car::operator <(const Car &carB) const {
return mLNumber < carB.mLNumber;
}
There's two problems in the code - first, logically, your operators are immutable on the type - they don't change the objects, they only analyze them, and you should be able to call them on immutable (const) objects. So, as alestanis pointed out, make them const (all operators and the getter method).
Second, < == and > are binary operators. There's two options to implement them: as free operators, or as members. You went with members, which is okay, but:
bool Car::operator <(const Car &carA, const Car &carB)
doesn't declare a binary operator. When you implement an operator as a member, the first parameter is implicitly the current object (*this), so it should be
bool Car::operator <(const Car &carB) const
The free operator would look like:
bool operator < (const Car& carA, const Car& carB);
Note that const on this one doesn't make sense since it's not a member. However, note that the first parameter (carA) is marked as const, which corresponds to the const applied to the method in the member version (which, under the hood, marks this as const).
It would help to see where you're calling these operators.
Your second version with two Car arguments should be global operators. So drop the Car:: from the definitions if you use them. Move the declarations out of the Car class' body, too.
Since your calling GetNum on a const Car object, the Car::GetNum function also needs to be const. The dirtier way to do this is to cast away the const-ness, but that is frowned upon.
Your error is when you want to compare one const object and you operators is not marked asconst, as a general rule, you should always mark functions and operators that do not change your object as const and this make life much easier. For example:
bool Car::operator ==(const Car &car) const // <-- This function is const
{
return mLNumber == car.GetNum();
}
The problem is that car::GetNum() isn't declared const, so you can't call it on const instances of car. The operators take a const Car &carB as argument, so you can't call GetNum() on carB, since carB is a const object, but GetNum() has not been declared const.
You should get into the habit of declaring all functions that don't modify the object as const. To declare a function as const, simply append const after the closing parenthesis. Both in the declaration, as well as the definition. For example:
class car {
// ...
void car::foo() const;
// ...
};
void car::foo() const
{ /* ... */ }
Or, if you're defining it inline inside the class declaration:
class car {
// ...
void car::foo() const
{ /* ... */ }
// ...
};
Although not strictly necessary in this particular case (meaning this isn't why the code doesn't compile), the operators themselves should also be declared const for the same reason (so that you can use them also on const objects.)
In the first case:
Your operators do not change data of operands, then it should be made const:
bool Car::operator <(const Car &carB) const {
//^^^^^
return mLNumber < carB.GetNum();
}
bool Car::operator >(const Car &carB) const {
// ^^^^^
return mLNumber > carB.GetNum();
}
int Car::GetNum() const
//^^^^^
{
return mLNumber;
}
In the second case, when operators accept 2 arguments, they should be implemented as free functions:
bool operator <(const Car &carA, const Car &carB)
{
return carA.GetNum() < carB.GetNum();
}
bool operator >(const Car &carA, const Car &carB)
{
return carA.GetNum() > carB.GetNum();
}

Error using std::find with operator==

I am getting an error using std::find on the following structure ...
struct ComplianceOrderRecord {
explicit ComplianceOrderRecord(IOrder& order);
bool operator ==(const ComplianceOrderRecord& other) const;
double price;
};
inline bool ComplianceOrderRecord::operator ==(const ComplianceOrderRecord& other) const {
return price == other.price;
}
I use it as follows...
inline void Compliance::RemoveComplianceOrderRecord(const ComplianceOrderRecord& order) {
auto it = std::find(m_compliantOrderList.begin(),
m_compliantOrderList.end(), order);
if(it == m_compliantOrderList.end()) {
return;
}
m_compliantOrderList.erase(it);
}
The error is...
error C2679: binary '==' : no operator found which takes a right-hand operand of type 'const ComplianceOrderRecord' (or there is no acceptable conversion)
Any help in understanding this error would be very appreciated.
Your operator== should be a const member, or even better, a freestanding function.
This error can be reproduced if m_compliantOrderList is not a container<ComplianceOrderRecord >. (Perhaps it is a container of pointers, or some other completely unrelated class.
Edit:
Your equality operator can compare two instances of ComplianceOrderRecord, but find needs to compare a pointer against an object. Overloading an operator to perform this kind of comparison would be bizarre, so you could use find_if with a custom predicate, such as:
struct RecordIsEqualTo
{
const ComplianceOrderRecord* record;
RecordIsEqualTo(const ComplianceOrderRecord& r): record(&r) {}
bool operator() (const ComplianceOrderRecord* r) const { return *record == *r; }
};
std::find_if(m_compliantOrderList.begin(), m_compliantOrderList.end(),
RecordIsEqualTo(order) );
or a lambda version thereof.
Your operator== function should be const. As it is, you can't call it on a const object (or a reference to const.
Try a const method:
inline bool ComplianceOrderRecord::operator ==(const ComplianceOrderRecord& other) const {
return price == other.price;
}

c++ property class structure

I have a c++ project being developed in QT. The problem I'm running in to is I am wanting to have a single base class that all my property classes inherit from so that I can store them all together. Right now I have:
class AbstractProperty
{
public:
AbstractProperty(QString propertyName);
virtual QString toString() const = 0;
virtual QString getName() = 0;
virtual void fromString(QString str) = 0;
virtual int toInteger() = 0;
virtual bool operator==(const AbstractProperty &rightHand) = 0;
virtual bool operator!=(const AbstractProperty &rightHand) = 0;
virtual bool operator<(const AbstractProperty &rightHand) = 0;
virtual bool operator>(const AbstractProperty &rightHand) = 0;
virtual bool operator>=(const AbstractProperty &rightHand) = 0;
virtual bool operator<=(const AbstractProperty &rightHand) = 0;
protected:
QString name;
};
then I am implementing classes such as PropertyFloat and PropertyString and providing implementation for the comparator operators based on the assumption that only strings are being compared with strings and so on. However the problem with this is there would be no compiletime error thrown if i did
if(propertyfloat a < propertystring b)
however my implementation of the operators for each derived class relies on them both being the same derived class. So my problem is I cant figure out how to implement a property structure so that I can have them all inherit from some base type but code like what I have above would throw a compile time error.
Any ideas on how this can be done? For those familiar with QT I tried using also a implementation with QVariant however QVariant doesn't have operators < and > defined in itself only in some of its derived classes so it didn't work out.
What my end goal is, is to be able to generically refer to properties. I have an element class that holds a hashmap of properties with string 'name' as key and the AbstractProperty as value. I want to be able to generically operate on the properties. i.e. if I want to get the max and min values of a property given its string name I have methods that are completely generic that will pull out the associated AbstactProperty from each element and find the max/min no matter what the type is. so properties although initially declared as PropertyFloat/PropertyString they will be held generically.
What if instead of making the comparator operators members of the class you make them global functions?
If you did that, then you could make an operator for each given type and control which types can compare to each other:
bool operator==(const PropertyFloat &leftHand, const PropertyFloat &rightHand);
bool operator==(const PropertyString &leftHand, const PropertyString &rightHand);
The compiler would complain anytime that you did this:
if(propertyfloat a == propertystring b)
Now, in order to access the private data necessary for the comparison, make these global functions "friends" of the derived classes.
I had a similar problem in one of my designs until I meditated over it. I realized that having comparison operators in the Base class was wrong. As you have found out, a comparison method in the base class is comparing any combination of descendant classes. This is bad Karma.
A better approach is to define the comparison operators in the descendant classes. This will help the compiler prevent people using the operators with different types. The side effect of this is that one can't compare objects by dereferencing a pointer to the base class (which will be a good thing).
Another useful tool are the Boost comparison templates. Look for equality_comparable.
Another solution is to use the Curiously Recurring Template Pattern. This allows a templated class to define comparison operators based on a derived class.
Example:
template <class Descendant>
struct Numeric_Field
{
Descendant m_value;
bool operator==(const Descendant& d)
{
return m_value == d.value;
}
bool operator!=(const Descendant& d)
{
return !(*this == d);
}
bool operator< (const Descendant& d)
{
return m_value < d.m_value;
}
bool operator<=(const Descendant& d)
{
return (*this < d) || (*this == d);
}
bool operator> (const Descendant& d)
{
return !(*this <= d);
}
bool operator>=(const Descendant& d)
{
return !(*this < d);
}
protected:
Numeric_Field(const Descendant& new_value = 0)
: m_value(new_value)
{ ;}
};
This could be made a little more generic by replacing m_value by using pure virtual protected setters and getters:
template <class Descendant_Type>
struct Numeric_Field_2
{
virtual const Descendant_Type get_value(void) const = 0;
virtual void set_value(const Descendant& new_value) = 0;
bool operator==(const Descendant_Type& dt)
{
return get_value() == dt.get_value();
}
bool operator< (const Descendant_Type& dt)
{
return get_value() < dt.get_value();
}
};
At this point, you could pass around pointers to Numeric_Field wherever a comparison is needed. I believe this is only a typing saver.