How to implement the comparison function in this case?
void remove(const Object1 &object1) {
for(auto &object2 : objectVector) {
if(object1 == object2) {
/*....... */
}
}
}
You are asking 2 questions:
How can objects be made comparable:
By implementing operator== for the class. Be sure you override operator != then too.
As a member function:
bool Object1::operator ==(const Object1 &b) const
{
// return true if *this equals b;
}
Or as a free function:
bool operator ==(const Object1 &a, const Object1 &b)
How can objects with a given value be removed from a vector:
The easiest way is to use std::remove:
objectVector.erase(std::remove(objectVector.begin(), objectVector.end(), object1), objectVector.end());
You can remove objects also while iterating through the vector, but you have to keep in mind that the vector iterator is invalidated then. You may not further iterate on the vector then.
An object of your class can contain different types and number of members so let's say that you have a class A:
class A{
int x,
float y;
char* z;
};
And you have two instances:
A a1;
A a2;
To compare:
if(a1 == a2) // compile-time error
;// DoSomeThing
Above you get the error because the compiler doesn't know which fields will be compared against each other. The solution is to overload the equals operator "==" to work on objects of your class.
class Student{
public:
Student(std::string, int age);
std::string getName()const;
int getAge()const;
bool operator == (const Student&);
private:
std::string name;
int age;
};
Student::Student(std::string str, int x) :
name(str), age(x){
}
bool Student::operator == (const Student& rhs){
return age == rhs.age;
}
std::string Student::getName()const{
return name;
}
int Student::getAge()const{
return age;
}
int main(){
Student a("Alpha", 77);
Student b("Beta", 49);
if(a == b)
std::cout << a.getName() << " is the same age as " <<
b.getName() << std::endl;
cout << endl << endl;
return 0;
}
Now the compiler knows how to compare objects of your class and know what the equals operator compares on your ojects members.
if object is a class you can override the operator == in the class as a friend function, or you can implement your own function bool isEqual(Object1 o1, Object1 o2) { if(something) return true; return false; }
Related
I saw the others question on Stack Overflow but they only answered a part of it.
suppose we have a class-
class student
{
public:
string name;
student(string a)
{
name = a;
cout << "parmeteised const." << endl;
}
student(student &a)
{
name = a.name;
cout << "Copy const." << endl;
}
};
int main()
{
student a("Vyom");
student c(a);
if (a == c)
{
cout << "same";
}
return 0;
}
This does not compile and gives an error-
no operator "==" matches these operands -- operand types are: student == student
Now I know that this is wrong and I would have to overload the operator to do so.
My Doubts:
We have argument &a in the copy constructor but we input only a while making an object c.
If point 1 is true and valid then it probably means a stands for the memory location of the object.
if point 2 is true and valid then why can't I compare memory locations of a and c
(I know memory locations will be in hexadecimal but there must be a way to convert them into int and then compare).
I am beginner, please help me clarify my doubts.
We have argument &a in the copy constructor but we input only a while making an object c.
In the function student(student &a) variable 'a' is reference on a student. It is not a pointer (student* a).
You will have to implement the comparison operator == if you want to compare two student objects:
operator_comparison
You have to overload (implement) == operator for the class. Below is a sample == operator implementation for your class -
bool operator==(const student& a) const {
if (a.name == this->name) return true;
return false;
}
Now your code should look like below -
#include <iostream>
using namespace std;
class student
{
public:
string name;
student(string a)
{
name = a;
cout << "parmeteised const." << endl;
}
student(student &a)
{
name = a.name;
cout << "Copy const." << endl;
}
bool operator==(const student& a) const {
if (a.name == this->name) return true;
return false;
}
};
int main()
{
student a("Vyom");
student c(a);
if (a == c)
{
cout << "same";
}
return 0;
}
I have this interesting assignment where I have a std::map of CTurist (previous class) and unsigned variable. Here's the code:
class CTurist
{
protected:
string tName;
int age;
public:
CTurist() {};
CTurist(string name, int age2)
{
tName = name;
age = age2;
}
bool operator<(const CTurist& e) const
{
return age < e.age;
}
friend ostream& operator<<(ostream& os, const CTurist&& e);
friend ifstream& operator>>(ifstream& is, CTurist&& e);
};
class CHotel:public CTurist
{
protected:
string hName;
int stars;
int beds;
map<CTurist, unsigned> Turisti;
public:
unsigned Sum = 0;
CHotel(){};
CHotel(string hName2, int zvezdi, int legla)
{
hName = hName;
stars = zvezdi;
beds = legla;
}
int Compare()
{
list<CTurist*> list;
int br=0;
CTurist vyzrast;
map<CTurist, unsigned>::iterator it = Turisti.begin();
while (it != Turisti.end())
{
if (it->first < vyzrast)
{
br++;
}
else
{
list.push_back(std::move(&it->first));
}
}
}
};
I know it's quite a long one, but I thought it's best to give you all the information.
Now, the int Compare() function AT THE BOTTOM is the one causing me problems.
I have to check if the age of the tourists is above or below a parameter which I've called vyzrast here. We're comparing the age. If it's below, it's quite straight forward.
If it's above though, I have to add those Tourists to a list<CTurist*>, aka. to a list of pointers. If I make the list from objects, not pointers. No luck with this, hence why I'm looking for suggestions how to fix it here.
Why are you using rvalue references for your operator overloads? You should be using const CTurist & for operator<< and CTurist& for operator>>. And you should be using std::istream for operator>>:
friend ostream& operator<<(ostream& os, const CTurist &e);
friend istream& operator>>(istream& is, CTurist &e);
Aside from that, there is no reason for Compare() to use std::move() at all when populating the std::list, as it is adding pointers, not moving actual objects.
Compare() doesn't won't correctly for several reasons:
it->first is an actual const CTurist object, but your std::list is expecting CTurist* pointers. std::map keys are const, so &it->first is a CTurist const * pointer (non-const pointer to const object), not a CTurist* pointer (non-const pointer to non-const object) like you are expecting.
Your vyzrast object is uninitialized. You are not assigning any value to its age (and tName) member at all, so the result of your comparisons is indeterminate.
You are not incrementing your it iterator on each loop iteration, so you are stuck in an infinite loop if the std::map is not empty.
Try something more like this instead:
int Compare()
{
std::list<const CTurist *> clist;
int br = 0;
CTurist vyzrast("", SomeAgeValueHere);
std::map<CTurist, unsigned>::iterator it = Turisti.begin();
while (it != Turisti.end())
{
if (it->first < vyzrast)
{
br++;
}
else
{
clist.push_back(&it->first);
}
++it;
}
// use clist as needed...
return SomeValueHere;
}
Live Demo
I would like to add an option to make a chained comparison on objects of MyClass. For example:
MyClass one;
MyClass two;
MyClass three;
/*....*/
if (one == two == three){
/*....*/
}
So that if all are equal it will return true, else it will return false.
I currently have this operator overload that works fine when comparing only two instances of MyClass:
bool operator==(const MyClass &other);
I understand that one==two==three is equal to ((one==two)==three) so I guess that should change my operator== to be something like:
MyClass& operator==(const MyClass &other);
But I couldn't manage to understand how to complete this in order to be able to compare more than two instances in a row (chained).
As pointed out in comments, it's not good to break the usual semantics in such a way. The Principle of least Astonishment should be followed as mentioned.
But I couldn't manage to understand how to complete this in order to be able to compare more than two instances in a row (chained).
Not that I think it's really a good idea to do so1, but here's a working solution:
#include <iostream>
using namespace std;
class MyClass {
public:
MyClass(int x_) : x(x_), isfalse(false) {}
const MyClass& operator==(const MyClass& rhs) const {
if(!isfalse && x == rhs.x) {
return rhs;
}
return FalseInst;
}
operator bool() const {
return !isfalse;
}
private:
int x;
MyClass() : x(), isfalse(true) {}
const bool isfalse;
static MyClass FalseInst;
};
MyClass MyClass::FalseInst;
int main()
{
MyClass one(1);
MyClass two(1);
MyClass three(1);
if(one == two == three) {
cout << "Yay!" << endl;
}
MyClass four(1);
MyClass five(0);
MyClass six(0);
if(!(four == (five == six))) {
cout << "Yay!" << endl;
}
}
Live Demo
1) Note the warning issued by the compiler.
As a purely theoretical problem, here is a way to solve it:
#include <iostream>
using namespace std;
class A {
public:
int x;
A(int x = 0) : x(x) {}
struct Cmp {
const A *ptr;
mutable bool val;
operator bool() const {
return val;
}
const Cmp &operator == (const A &other) const {
return other == *this;
}
};
bool isEqualTo (const A &other) const {
return x == other.x;
}
Cmp operator == (const A &other) const {
return {this, isEqualTo(other)};
}
const Cmp &operator == (const Cmp &other) const {
//other.val = other.val && (*this == *other.ptr).val;
other.val &= other.ptr->isEqualTo(*this);
return other;
}
};
int main() {
cout << (A(10) == A(10) == A(10)) << endl;
cout << (A(10) == A(9) == A(10)) << endl;
return 0;
}
i'm new in programming and i'm trying to search an element in a list of class and i did this:
string x;
cin >> x;
list<Person>::iterator findIter = std::find(ListPerson.begin(), ListPerson.end(), x);
but it seem like i must overload the operator== to work, i did this:
friend bool operator== (Person &P1, Person &P2);
bool operator== (Person& P1, Person& P2)
{
return (P1.Name == P2.Name);
}
but it doesn't work i got always this error : c2678 binary '==' no operator found which takes a left-hand operand of type Person.
Thank you for helping !
Have you tried declaring the parameters as constant references? A comparison operator does not need to have side-effects.
The following works for me, and prints yeah:
#include <iostream>
using namespace std;
struct P {
const int x;
P(int x) {
this->x = x;
}
};
bool operator== (const P & p1, const P &p2) {
return p1.x == p2.x;
}
int main()
{
P x(0), y(0), z(1);
if (x == y) {
cout << "yeah" << endl;
}
if (y == z) {
cout << "nope" << endl;
}
}
Of course you might need to declare the operator== as a friend function if you want to do a comparison over private instance variables.
class P {
int x;
public:
P(int x) {
this->x = x;
}
friend bool operator== (const P &p1, const P &p2);
};
Your friend bool operator== declaration should be inside the class declaration. Next, pass by const reference instead, as rvalues cannot bind to non-const references and also the std::find expects its compared-to element by const reference. So your operator== should be able to compare const references, and non-const ones will not do since they will discard const qualifiers. To fix, declare
friend bool operator==(const Person &P1, const Person &P2);
Live working example here.
I want to make a typedef struct called pos (from position) that stores coordinates x and y. I am trying to overload some operators for this struct, but it does not compile.
typedef struct {
int x;
int y;
inline pos operator=(pos a) {
x=a.x;
y=a.y;
return a;
}
inline pos operator+(pos a) {
return {a.x+x,a.y+y};
}
inline bool operator==(pos a) {
if (a.x==x && a.y== y)
return true;
else
return false;
}
} pos;
I also wanted to know the difference between this:
inline bool operator==(pos a) {
if(a.x==x && a.y== y)
return true;
else
return false;
}
And this:
bool operator==(pos a) const {
if(a.x==x && a.y== y)
return true;
else
return false;
}
The breakdown of your declaration and its members is somewhat littered:
Remove the typedef
The typedef is neither required, not desired for class/struct declarations in C++. Your members have no knowledge of the declaration of pos as-written, which is core to your current compilation failure.
Change this:
typedef struct {....} pos;
To this:
struct pos { ... };
Remove extraneous inlines
You're both declaring and defining your member operators within the class definition itself. The inline keyword is not needed so long as your implementations remain in their current location (the class definition)
Return references to *this where appropriate
This is related to an abundance of copy-constructions within your implementation that should not be done without a strong reason for doing so. It is related to the expression ideology of the following:
a = b = c;
This assigns c to b, and the resulting value b is then assigned to a. This is not equivalent to the following code, contrary to what you may think:
a = c;
b = c;
Therefore, your assignment operator should be implemented as such:
pos& operator =(const pos& a)
{
x = a.x;
y = a.y;
return *this;
}
Even here, this is not needed. The default copy-assignment operator will do the above for you free of charge (and code! woot!)
Note: there are times where the above should be avoided in favor of the copy/swap idiom. Though not needed for this specific case, it may look like this:
pos& operator=(pos a) // by-value param invokes class copy-ctor
{
this->swap(a);
return *this;
}
Then a swap method is implemented:
void pos::swap(pos& obj)
{
// TODO: swap object guts with obj
}
You do this to utilize the class copy-ctor to make a copy, then utilize exception-safe swapping to perform the exchange. The result is the incoming copy departs (and destroys) your object's old guts, while your object assumes ownership of there's. Read more the copy/swap idiom here, along with the pros and cons therein.
Pass objects by const reference when appropriate
All of your input parameters to all of your members are currently making copies of whatever is being passed at invoke. While it may be trivial for code like this, it can be very expensive for larger object types. An exampleis given here:
Change this:
bool operator==(pos a) const{
if(a.x==x && a.y== y)return true;
else return false;
}
To this: (also simplified)
bool operator==(const pos& a) const
{
return (x == a.x && y == a.y);
}
No copies of anything are made, resulting in more efficient code.
Finally, in answering your question, what is the difference between a member function or operator declared as const and one that is not?
A const member declares that invoking that member will not modifying the underlying object (mutable declarations not withstanding). Only const member functions can be invoked against const objects, or const references and pointers. For example, your operator +() does not modify your local object and thus should be declared as const. Your operator =() clearly modifies the local object, and therefore the operator should not be const.
Summary
struct pos
{
int x;
int y;
// default + parameterized constructor
pos(int x=0, int y=0)
: x(x), y(y)
{
}
// assignment operator modifies object, therefore non-const
pos& operator=(const pos& a)
{
x=a.x;
y=a.y;
return *this;
}
// addop. doesn't modify object. therefore const.
pos operator+(const pos& a) const
{
return pos(a.x+x, a.y+y);
}
// equality comparison. doesn't modify object. therefore const.
bool operator==(const pos& a) const
{
return (x == a.x && y == a.y);
}
};
EDIT OP wanted to see how an assignment operator chain works. The following demonstrates how this:
a = b = c;
Is equivalent to this:
b = c;
a = b;
And that this does not always equate to this:
a = c;
b = c;
Sample code:
#include <iostream>
#include <string>
using namespace std;
struct obj
{
std::string name;
int value;
obj(const std::string& name, int value)
: name(name), value(value)
{
}
obj& operator =(const obj& o)
{
cout << name << " = " << o.name << endl;
value = (o.value+1); // note: our value is one more than the rhs.
return *this;
}
};
int main(int argc, char *argv[])
{
obj a("a", 1), b("b", 2), c("c", 3);
a = b = c;
cout << "a.value = " << a.value << endl;
cout << "b.value = " << b.value << endl;
cout << "c.value = " << c.value << endl;
a = c;
b = c;
cout << "a.value = " << a.value << endl;
cout << "b.value = " << b.value << endl;
cout << "c.value = " << c.value << endl;
return 0;
}
Output
b = c
a = b
a.value = 5
b.value = 4
c.value = 3
a = c
b = c
a.value = 4
b.value = 4
c.value = 3
Instead of typedef struct { ... } pos; you should be doing struct pos { ... };. The issue here is that you are using the pos type name before it is defined. By moving the name to the top of the struct definition, you are able to use that name within the struct definition itself.
Further, the typedef struct { ... } name; pattern is a C-ism, and doesn't have much place in C++.
To answer your question about inline, there is no difference in this case. When a method is defined within the struct/class definition, it is implicitly declared inline. When you explicitly specify inline, the compiler effectively ignores it because the method is already declared inline.
(inline methods will not trigger a linker error if the same method is defined in multiple object files; the linker will simply ignore all but one of them, assuming that they are all the same implementation. This is the only guaranteed change in behavior with inline methods. Nowadays, they do not affect the compiler's decision regarding whether or not to inline functions; they simply facilitate making the function implementation available in all translation units, which gives the compiler the option to inline the function, if it decides it would be beneficial to do so.)
try this:
struct Pos{
int x;
int y;
inline Pos& operator=(const Pos& other){
x=other.x;
y=other.y;
return *this;
}
inline Pos operator+(const Pos& other) const {
Pos res {x+other.x,y+other.y};
return res;
}
const inline bool operator==(const Pos& other) const {
return (x==other.x and y == other.y);
}
};
bool operator==(pos a) const{ - this method doesn't change object's elements.
bool operator==(pos a) { - it may change object's elements.