Operater < overloading for struct problem

F

Frank

Hello everyone,

I am having trouble overloading the < operator for an assignment. I
use a struct that contains information and I would like to sort this
structure using STL sort with my own criteria of sorting. Basically, I
would like to sort on visitor count of the Attraction structure.
However, it never uses the < overloaded operator with my code.

Handler.h:

#ifndef H_HANDLER //Guard
#define H_HANDLER

#include <iostream>
#include <vector>
using namespace std;

struct Attraction {
string name;
int visitors;
};

class Handler { //Define the class Handler

private:
vector<Attraction*> attractions ;
vector<Attraction*>::iterator p ;

public: //Public functions
~Handler();
void addAttraction(string name, int visitors);
void printAttractions();
};


#endif

and in the Handler.cpp I have:

Handler.cpp - snippet:

bool operator<(const Attraction& a,const Attraction& b){
return a.visitors < b.visitors;
}

Here is the function that performs the sort after adding a value:

void Handler::addAttraction(string name, int visitors){

Attraction *attr;
attr=new Attraction();

attr->name=name;
attr->visitors=visitors;


attractions.push_back(attr);
sort(attractions.begin(),attractions.end());

}

However, whatever I do, it will never use the overloaded < operator
for sorting. What am I doing wrong? If I add the overloaded function
in the header it starts complaining because it will also be inserted
into the main program which is confusing since I have a guard around
the header file.

Regards,
Frank
 
V

Victor Bazarov

Frank said:
I am having trouble overloading the < operator for an assignment. I
use a struct that contains information and I would like to sort this
structure using STL sort with my own criteria of sorting. Basically, I
would like to sort on visitor count of the Attraction structure.
However, it never uses the < overloaded operator with my code.

Handler.h:

#ifndef H_HANDLER //Guard
#define H_HANDLER

#include <iostream>
#include <vector>
using namespace std;

struct Attraction {
string name;
int visitors;
};

class Handler { //Define the class Handler

private:
vector<Attraction*> attractions ;
vector<Attraction*>::iterator p ;

public: //Public functions
~Handler();
void addAttraction(string name, int visitors);
void printAttractions();
};


#endif

and in the Handler.cpp I have:

Handler.cpp - snippet:

bool operator<(const Attraction& a,const Attraction& b){
return a.visitors < b.visitors;
}

Here is the function that performs the sort after adding a value:

void Handler::addAttraction(string name, int visitors){

Attraction *attr;
attr=new Attraction();

attr->name=name;
attr->visitors=visitors;


attractions.push_back(attr);
sort(attractions.begin(),attractions.end());

}

However, whatever I do, it will never use the overloaded < operator
for sorting. What am I doing wrong?

Your operator< is defined for _objects_, but your vector is storing
_pointers_. Drop the 'new', drop the pointers, keep objects, and
everything will be fine.

You can declare/define a local Attraction object in 'addAttraction'
and then push_back it, the vector will make a copy.

V
 
M

mlimber

Hello everyone,

I am having trouble overloading the < operator for an assignment. I
use a struct that contains information and I would like to sort this
structure using STL sort with my own criteria of sorting. Basically, I
would like to sort on visitor count of the Attraction structure.
However, it never uses the < overloaded operator with my code.

Handler.h:

#ifndef H_HANDLER //Guard
#define H_HANDLER

#include <iostream>
#include <vector>
using namespace std;

struct Attraction {
string name;
int visitors;

};

class Handler { //Define the class Handler

private:
vector<Attraction*> attractions ;
vector<Attraction*>::iterator p ;

public: //Public functions
~Handler();
void addAttraction(string name, int visitors);
void printAttractions();

};

#endif

and in the Handler.cpp I have:

Handler.cpp - snippet:

bool operator<(const Attraction& a,const Attraction& b){
return a.visitors < b.visitors;
}

Here is the function that performs the sort after adding a value:

void Handler::addAttraction(string name, int visitors){

Attraction *attr;
attr=new Attraction();

attr->name=name;
attr->visitors=visitors;

attractions.push_back(attr);
sort(attractions.begin(),attractions.end());

}

However, whatever I do, it will never use the overloaded < operator
for sorting. What am I doing wrong? If I add the overloaded function
in the header it starts complaining because it will also be inserted
into the main program which is confusing since I have a guard around
the header file.

I suspect the fundamental problem is that you are sorting pointers
rather than objects. In other words, std::sort works on the value_type
of the container, which in your case is Attraction*, not Attraction.

So, do you need to operator on the Attraction object polymorphically?
If not, don't use pointers; just allocate it on the stack, and let
vector make a copy (assuming attractions is now of type
vector<Attraction>:

void Handler::addAttraction( const string& name, const int visitors )
{
const Attraction attr = { name, visitors };
attractions.push_back(attr);
sort(attractions.begin(),attractions.end());
}

Note also that I changed the function parameters to const (see
http://www.parashift.com/c++-faq-lite/const-correctness.html) and the
string to a reference so it doesn't make an additional copy (see
http://www.parashift.com/c++-faq-lite/references.html).

If you do need to use it polymorphically and to store it in a vector,
prefer smart pointers such as std::tr1::shared_ptr (aka
boost::shared_ptr) or one of the smart pointers found in this FAQ and
those following:

http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.22

BTW, you could put just the function prototype for your operator< in
the header or you could declare it "inline" to get rid of the
duplication problem.

Cheers! --M
 
R

red floyd

Frank wrote:

Victor and mlimber have addressed your main issue. I'd like to address
one other item.
Handler.h:

#ifndef H_HANDLER //Guard
#define H_HANDLER

#include <iostream>
#include <vector>
using namespace std;

Do *NOT* put "using namespace std;" into a header file. It can
seriously mess up other code. It should only go into non-header files,
after all include directives.
 
F

Frank

Frank wrote:

Victor and mlimber have addressed your main issue. I'd like to address
one other item.




Do *NOT* put "using namespace std;" into a header file. It can
seriously mess up other code. It should only go into non-header files,
after all include directives.


Thanks everyone for the quick response!
It works like a charm now,
Regards,
Frank
 
R

Roland Pibinger

Your operator< is defined for _objects_, but your vector is storing
_pointers_. Drop the 'new', drop the pointers, keep objects, and
everything will be fine.

Except that objects in the OO sense like Attraction, Handler, ...
usually are not copyable.
You can declare/define a local Attraction object in 'addAttraction'
and then push_back it, the vector will make a copy.

That's the problem.

Best regards,
Roland Pibinger
 
V

Victor Bazarov

Roland said:
Except that objects in the OO sense like Attraction, Handler, ...
usually are not copyable.

"Usually"? What in the world do you mean? See to original post for
clarification.
That's the problem.

REALLY? Do you mean that the OP's Attraction object is non-copiable?
Could you please elaborate?

V
 
M

mlimber

"Usually"? What in the world do you mean? See to original post for
clarification.



REALLY? Do you mean that the OP's Attraction object is non-copiable?
Could you please elaborate?

Roland's just being an OO purist. Objects in his world are always
polymorphic, but in C++'s multiple paradigms, they are not. In this
case, I don't think the OP was intending to use pure OO anyway, so our
answers sufficed.

Cheers! --M
 
R

Roland Pibinger

REALLY? Do you mean that the OP's Attraction object is non-copiable?
Could you please elaborate?

Objects (in the OO sense) are characterized by identity, state and
behavior. When you duplicate (copy) objects you get into trouble with
identity and state, e.g.

Account a1 (12345);
Account a2 = a1;
a1.deposit (100);
a2.withdraw (200);

What does it mean to copy the account with account number 12345? What
is the balance of this account now? To answer your question,
Attraction (whatever that exactly means in the example) is an object
(in the sense of OO) and should not be copied.

Best regards,
Roland Pibinger
 
R

Roland Pibinger

Roland's just being an OO purist. Objects in his world are always
polymorphic, but in C++'s multiple paradigms, they are not.

So 'C++'s multiple paradigms' have changed the paradigms? C++ has
changed the meaning of object (OO) and polymorphism?
 
K

kwikius

Objects (in the OO sense) are characterized by identity, state and
behavior. When you duplicate (copy) objects you get into trouble with
identity and state, e.g.

Account a1 (12345);
Account a2 = a1;
a1.deposit (100);
a2.withdraw (200);

What does it mean to copy the account with account number 12345? What
is the balance of this account now?

struct Account{

double value;
Account(double value_in) :value(value_in){}
Account(Account & other)
{
value = other.value;
other.value =0;
}

void deposit( double val)
{
value += val;
}
void withdraw(double val)
{
value -= val;
}
};

#include <iostream>
int main()
{
Account a1 (12345);

std::cout << a1.value <<'\n';

Account a2 = a1;
std::cout << a1.value <<'\n';

a1.deposit (100);
std::cout << a1.value <<'\n';

a2.withdraw (200);
}

output:

12345
0
100


I Am Joking of course :) :) :)
 
M

mlimber

So 'C++'s multiple paradigms' have changed the paradigms? C++ has
changed the meaning of object (OO) and polymorphism?

C++ has not changed the meaning of polymorphism, but because of its
multi-paradigmatic nature, not every "object" is an OO object either.

struct B { virtual void f(); };

B b;
b.f(); // Will invoke B::f() directly
B& bref = b;
bref.f(); // Will invoke B::f() indirectly

In this example "b" is not being used polymorphically in the first
invocation of B::f(), but it is in the second.

Cheers! --M
 
V

Victor Bazarov

Roland said:
Objects (in the OO sense) are characterized by identity, state and
behavior. When you duplicate (copy) objects you get into trouble with
identity and state, e.g.

Account a1 (12345);
Account a2 = a1;
a1.deposit (100);
a2.withdraw (200);

What does it mean to copy the account with account number 12345?

You made a copy of the C++ object. I see nothing bad about it.
What
is the balance of this account now?

How the F should I know? Youi didn't explain any behaviour of the
'Account' class.
To answer your question,
Attraction (whatever that exactly means in the example) is an object
(in the sense of OO) and should not be copied.

You seem confused a bit...

'12345' has nothing to do with the identity of the object. &a1 and &a2
are the identities of the objects. '12345' is just a value that takes
part in the object's behaviour. Now, the "identity issue" can be seen
if you *pretend* that the operation

Accout &ra1 = a1;

is actually "making a copy". It isn't, of course, since &ra1 == &a1.

In the account example you gave, the actual bank account associated in
some way with 'a1' and 'a2' *objects* (instances of the 'Account' type)
is a separate "object" that has little to do with the program, and only
exists in the model, which apparently is not very well represented by
the 'Account' class (in terms of copying, obviously, using the terms of
what seems to be the model you're alluding to).

In "pure" OOP, according to you, no copy can be made. That doesn't
sound like a good thing. In the real world copies are made all the
time. Perhaps making a copy means different thing to different people
and your meaning is different from the C++'s one? The saying we use
in a situation like this is "don't push your own charter in someone
else's monastery". If you'd like the other monastery to adopt your
charter (or to amend its charter according to some of your views), you
might want to explain instead of attacking the monastery's principles
and values.

V
 
R

Roland Pibinger

You made a copy of the C++ object. I see nothing bad about it.

So there is no problem?
How the F should I know? Youi didn't explain any behaviour of the
'Account' class.

So actually there is a problem! Why should copying need an
explanation?
You seem confused a bit...

The confusion is not on my side.
'12345' has nothing to do with the identity of the object. &a1 and &a2
are the identities of the objects. '12345' is just a value that takes
part in the object's behaviour.

Right, in C++ object identity by default is established as address.
'Object IDs' are necessary e.g. when the object is stored in a
database (and the memory address is lost). But that doesn't affect my
example at all.
Now, the "identity issue" can be seen
if you *pretend* that the operation

Accout &ra1 = a1;

is actually "making a copy". It isn't, of course, since &ra1 == &a1.

The example just shows what happens when you try to duplicate stateful
objects with identity. But ...
In the account example you gave, the actual bank account associated in
some way with 'a1' and 'a2' *objects* (instances of the 'Account' type)
is a separate "object" that has little to do with the program, and only
exists in the model, which apparently is not very well represented by
the 'Account' class (in terms of copying, obviously, using the terms of
what seems to be the model you're alluding to).

You seem to confirm my example. It makes no sense to have 2 instances
of the same underlying "object".
In "pure" OOP, according to you, no copy can be made. That doesn't
sound like a good thing.

Look at dedicated OO languages like Java. You can implement a
copy-constructor in Java but why should you duplicate an object?
In the real world copies are made all the
time. Perhaps making a copy means different thing to different people
and your meaning is different from the C++'s one?

Copies of _values_ are made all the time but not of objects. You need
to distinguish between objects and values, see e.g.
http://www.two-sdg.demon.co.uk/curbralan/papers/ValuedIdioms.pdf
The saying we use
in a situation like this is "don't push your own charter in someone
else's monastery". If you'd like the other monastery to adopt your
charter (or to amend its charter according to some of your views), you
might want to explain instead of attacking the monastery's principles
and values.

I don't have a 'charter' and use only vocabulary commonly applied in
software engineering. The downside of the 'multiparadigm' approach in
C++ is that one not only needs to understand multiple paradigms but
also know how to combine them in a reasonable way. Otherwise one will
tackle the problems with the wrong tools.

Best regards,
Roland Pibinger
 
V

Victor Bazarov

Roland said:
[..] The downside of the 'multiparadigm' approach in
C++ is that one not only needs to understand multiple paradigms but
also know how to combine them in a reasonable way. Otherwise one will
tackle the problems with the wrong tools.

No! You don't need to combine anything. There is no requirement
not to wear OO after Labor Day. There is no requirement to combine
any paradigms or do it in any "reasonable way". Any way that gets
you where you're going is good.

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

operator overloading 9
"Reusable" operator overloading for enum? 21
struct dynamic 6
friend function overloading 8
overloading ->() 19
What is overloading operator-> for? 2
overloading . 5
struct error 2

Members online

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,276
Latest member
Sawatmakal

Latest Threads

Top