 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
romayankin@mail.ru Guest
|
Posted: Wed Sep 15, 2004 12:51 am Post subject: safe and elegant way of overloading operator== |
|
|
I've searched through comp.lang.c++.moderated; comp.lang.vc.language
and many many other on-line recourses and could not find a safe and
neat solution for this problem when we consider class hierarchy. The
code that can reproduce the problem I'm talking about is below:
class B{
public:
B() : m_b(0){}
int m_b;
virtual bool operator==(const B& b)const
{
return this->m_b == b.m_b;
}
};
class D1 : public B{
public:
D1() : m_d1(1){}
int m_d1;
};
int main()
{
B* pb1 = new B;
D2* pd2 = new D2;
bool res = false;
//Here is it!
//When we compare any ***Base*** class with its ***child***
//we will call "BaseClass::operator==" which accepts
//operator==("const BaseClass &b")
res = (*pb1 == *pd2);
return 1;
}
Basically there are two approaches to resolve this problem.
1) We can specify as "friend" (actually we may not do it) and overload
all operators== for ***All*** existing in hierarchy "Base" classes
with types of their "Children". This is a bad practice as whenever we
add another class we may forget to add another overloaded operator==
for ***All*** its Base classes.
2)We can try using RTTI and we can try checking type at runtime:
bool operator==(const B& b)const
{
if(typeid(*this)==typeid(b))
return /*compare members*/;
else
return false;
}
BUT still we will have to much of unnecessary code to write as when we
define "operator==" for the "Derived" class we can't call
"BaseClass::operator==(oChild)" as we will receive "false" (see above:
expression typeid(BaseClass)==typeid(ChildClass) will alwayse return
false). Unfortunatly no *****_cast operator will help us.
The problem is: what is the 3d option that is safe and elegant?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
jakacki Guest
|
Posted: Wed Sep 15, 2004 9:51 am Post subject: Re: safe and elegant way of overloading operator== |
|
|
[...]
| Quote: | The
code that can reproduce the problem I'm talking about is
below:
[code edited]
class B {
... |
int m_b;
| Quote: | virtual bool operator==(const B& b);
};
class D1 : public B {
... |
int m_d1;
| Quote: | };
int main()
{
B* pb1 = new B;
D2* pd2 = new D2;
... |
... *pb1 == *pd2 ...
| Quote: | }
Basically there are two approaches to resolve this
problem.
1) We can specify as "friend" (actually we may not do it)
and overload
all operators== for ***All*** existing in hierarchy "Base"
classes
with types of their "Children". This is a bad practice as
whenever we
add another class we may forget to add another overloaded > operator==
for ***All*** its Base classes.
2)We can try using RTTI and we can try checking type at
runtime:
[...] |
How would you like to define, say,
operator==(const B&, const D1&)? What can you change with
respect to the original definition? If you substantially
change anything, then
*pb==*pd1 and *pb==*(B*)pd1
will give different results for some arguments. And that
would be plain wrong, because by deriving D1 publicly from
B you state, that any object of class D1 *is* an object of
class B. Thus it should not behave differently depending
on how you look at it (though D1* pointer or B* pointer).
Thus if you define operator== in concrete base class,
then you may want to redefine it for subclasses to get
better performance, but you should not change
functionality.
Perhaps you could post more information on your actual
problem, it seems to me that your may be trying to solve
it in a wrong way.
BR
Grzegorz
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Tokyo Tomy Guest
|
Posted: Wed Sep 15, 2004 6:25 pm Post subject: Re: safe and elegant way of overloading operator== |
|
|
[email]romayankin (AT) mail (DOT) ru[/email] wrote in message news:<569b4d15.0409140912.429fc0d7 (AT) posting (DOT) google.com>...
| Quote: | I've searched through comp.lang.c++.moderated; comp.lang.vc.language
and many many other on-line recourses and could not find a safe and
neat solution for this problem when we consider class hierarchy. The
code that can reproduce the problem I'm talking about is below:
|
I am sorry I cannot see your point. I found an error in your code as shown below.
With the correction of the error, my MSVC++6 compiled your code successfully.
| Quote: | class B{
public:
B() : m_b(0){}
int m_b;
|
Data member should be private.
| Quote: | virtual bool operator==(const B& b)const
{
return this->m_b == b.m_b;
|
You do not need this->.
| Quote: | }
};
class D1 : public B{
public:
D1() : m_d1(1){}
int m_d1;
|
Data member should be private.
| Quote: | };
int main()
{
B* pb1 = new B;
D2* pd2 = new D2;
|
error: shold be D1* pd2 = new D1;
| Quote: | bool res = false;
//Here is it!
//When we compare any ***Base*** class with its ***child***
//we will call "BaseClass::operator==" which accepts
//operator==("const BaseClass &b")
res = (*pb1 == *pd2);
|
res should be true. Two base classes are compared.
return 0 instead
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Bob Hairgrove Guest
|
Posted: Wed Sep 15, 2004 7:28 pm Post subject: Re: safe and elegant way of overloading operator== |
|
|
On 14 Sep 2004 20:51:19 -0400, [email]romayankin (AT) mail (DOT) ru[/email] wrote:
| Quote: | I've searched through comp.lang.c++.moderated; comp.lang.vc.language
and many many other on-line recourses and could not find a safe and
neat solution for this problem when we consider class hierarchy. The
code that can reproduce the problem I'm talking about is below:
class B{
public:
B() : m_b(0){}
int m_b;
|
Shouldn't m_b be declared private? Or at least protected?
| Quote: | virtual bool operator==(const B& b)const
{
return this->m_b == b.m_b;
}
};
class D1 : public B{
public:
D1() : m_d1(1){}
int m_d1;
};
int main()
{
B* pb1 = new B;
D2* pd2 = new D2;
bool res = false;
//Here is it!
//When we compare any ***Base*** class with its ***child***
//we will call "BaseClass::operator==" which accepts
//operator==("const BaseClass &b")
res = (*pb1 == *pd2);
return 1;
}
Basically there are two approaches to resolve this problem.
1) We can specify as "friend" (actually we may not do it) and overload
all operators== for ***All*** existing in hierarchy "Base" classes
with types of their "Children". This is a bad practice as whenever we
add another class we may forget to add another overloaded operator==
for ***All*** its Base classes.
2)We can try using RTTI and we can try checking type at runtime:
bool operator==(const B& b)const
{
if(typeid(*this)==typeid(b))
return /*compare members*/;
else
return false;
}
BUT still we will have to much of unnecessary code to write as when we
define "operator==" for the "Derived" class we can't call
"BaseClass::operator==(oChild)" as we will receive "false" (see above:
expression typeid(BaseClass)==typeid(ChildClass) will alwayse return
false). Unfortunatly no *****_cast operator will help us.
The problem is: what is the 3d option that is safe and elegant?
|
You could declare operator== protected in the base class and have each
derived class check the derived bits for equality, then pass on *this
== other to operator== in the base class, e.g.:
class B {
protected:
virtual bool operator==(const B&) const { /*...*/ }
};
class D (
private:
bool eq(const D&) const {
/* optional implementation of derived operator== */ }
public:
bool operator==(const D& d) const { return eq(d) && (*this==d); }
};
--
Bob Hairgrove
[email]NoSpamPlease (AT) Home (DOT) com[/email]
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ali Cehreli Guest
|
Posted: Wed Sep 15, 2004 11:41 pm Post subject: Re: safe and elegant way of overloading operator== |
|
|
[email]romayankin (AT) mail (DOT) ru[/email] wrote in message news:<569b4d15.0409140912.429fc0d7 (AT) posting (DOT) google.com>...
| Quote: | class B{
public:
B() : m_b(0){}
int m_b;
virtual bool operator==(const B& b)const
{
return this->m_b == b.m_b;
}
};
class D1 : public B{
public:
D1() : m_d1(1){}
int m_d1;
};
|
[...]
| Quote: | 2)We can try using RTTI and we can try checking type at runtime:
bool operator==(const B& b)const
{
if(typeid(*this)==typeid(b))
return /*compare members*/;
else
return false;
}
|
In the past, I've used a variation of that method for operator<, but
it should work for operator== as well.
Define 'bool operator==(B const & other) const;' in the base class but
call a private pure virtual isEqual member when the types are the
same:
if (typeid(*this) == typeid(other))
{
return isEqual(other);
}
else
{
return false;
}
In the most derived classes, you can trust the typeid check performed
in operator==, and do a static_cast in isEqual:
class D
{
int member_;
virtual bool isEqual(Base const & o) const
{
Derived const & other = static_cast
return member_ == other.member_;
}
/* ... */
};
I couldn't use a compiler to test this code. I hope there aren't many
errors :)
Ali
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Sven Rosiers Guest
|
Posted: Wed Sep 15, 2004 11:59 pm Post subject: Re: safe and elegant way of overloading operator== |
|
|
[email]romayankin (AT) mail (DOT) ru[/email] wrote:
| Quote: | The problem is: what is the 3d option that is safe and elegant?
|
The following might work. I leave the appreciation of its elegance to
your personal taste ;-)
Basically, you define a protected virtual member function do_equals().
operator==() is a free function (always make operator==() a free
function, otherwise *base == *derived will work, but *derived == *base
will not), which contains the typeid check, and then dispatches to
do_equals(). Derived classes dispatch to the base::do_equals before
comparing their own bits.
#include <iostream>
#include <typeinfo>
using namespace std;
class base {
public:
explicit base(int value) : value_(value) {};
virtual ~base() {};
protected:
friend bool operator==(base const&, base const&);
virtual bool do_equals(base const& other) const {
return value_ == other.value_;
};
int value_;
};
class derived : public base {
public:
explicit derived(int value, int count) : base(value), count_(count) {}
protected:
bool do_equals(base const& other) const {
derived const& d = dynamic_cast<derived const&>(other);
return base::do_equals(other) && (count_ == d.count_);
};
int count_;
};
bool operator==(base const& lhs, base const& rhs) {
if (typeid(lhs) != typeid(rhs)) {
return false;
}
return lhs.do_equals(rhs);
}
int main() {
base* b1 = new base(1);
derived* d1 = new derived(1, 101);
derived* d2 = new derived(1, 102);
cout << (*b1 == *d1) << endl;
cout << (*d1 == *d1) << endl;
cout << (*d1 == *d2) << endl;
}
Regards,
Sven R.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Milivoj Davidov Guest
|
Posted: Thu Sep 16, 2004 11:07 am Post subject: Re: safe and elegant way of overloading operator== |
|
|
[email]romayankin (AT) mail (DOT) ru[/email] wrote in message news:<569b4d15.0409140912.429fc0d7 (AT) posting (DOT) google.com>...
| Quote: | I've searched through comp.lang.c++.moderated; comp.lang.vc.language
and many many other on-line recourses and could not find a safe and
neat solution for this problem when we consider class hierarchy. The
code that can reproduce the problem I'm talking about is below:
|
I have a feeling that you are trying to solve the
double dispatch / multiple dispatch problem (or
multimethods problem). That's not easy, but the
problem's been solved.
You could read Andrei Alexandrescu's first book and
study his Loki library's MultiMethods.h header:
"Modern C++ Design: Generic Programming and Design Patterns Applied"
by Andrei Alexandrescu, Addison-Wesley 2001, ISBN: 0201704315
http://www.moderncppdesign.com/
Loki library:
http://sourceforge.net/projects/loki-lib/
See also Danil Shopyrin's article:
http://www.codeproject.com/cpp/mmcppfcs.asp
Milivoj Davidov
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Bob Hairgrove Guest
|
Posted: Fri Sep 17, 2004 3:14 am Post subject: Re: safe and elegant way of overloading operator== |
|
|
On 15 Sep 2004 15:28:58 -0400, Bob Hairgrove <invalid (AT) bigfoot (DOT) com>
wrote:
| Quote: | You could declare operator== protected in the base class and have each
derived class check the derived bits for equality, then pass on *this
== other to operator== in the base class, e.g.:
class B {
protected:
virtual bool operator==(const B&) const { /*...*/ }
};
class D (
private:
bool eq(const D&) const {
/* optional implementation of derived operator== */ }
public:
bool operator==(const D& d) const { return eq(d) && (*this==d); }
};
|
oops ... we seem to have some endless recursion here.
Quick fix:
Either explicitly qualify operator== in the derived implementation,
i.e.:
bool D::operator==(const D& d) const {
return eq(d)
&& B::operator==(d);
}
or use a differently named function in the base class as others have
already suggested.
--
Bob Hairgrove
[email]NoSpamPlease (AT) Home (DOT) com[/email]
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
romayankin@mail.ru Guest
|
Posted: Mon Sep 27, 2004 8:50 pm Post subject: Re: safe and elegant way of overloading operator== |
|
|
[email]romayankin (AT) mail (DOT) ru[/email] wrote in message news:<569b4d15.0409140912.429fc0d7 (AT) posting (DOT) google.com>...
| Quote: | I've searched through comp.lang.c++.moderated; comp.lang.vc.language
and many many other on-line recourses and could not find a safe and
neat solution for this problem when we consider class hierarchy. The
code that can reproduce the problem I'm talking about is below:
class B{
public:
B() : m_b(0){}
int m_b;
virtual bool operator==(const B& b)const
{
return this->m_b == b.m_b;
}
};
class D1 : public B{
public:
D1() : m_d1(1){}
int m_d1;
};
int main()
{
B* pb1 = new B;
D2* pd2 = new D2;
bool res = false;
//Here is it!
//When we compare any ***Base*** class with its ***child***
//we will call "BaseClass::operator==" which accepts
//operator==("const BaseClass &b")
res = (*pb1 == *pd2);
return 1;
}
Basically there are two approaches to resolve this problem.
1) We can specify as "friend" (actually we may not do it) and overload
all operators== for ***All*** existing in hierarchy "Base" classes
with types of their "Children". This is a bad practice as whenever we
add another class we may forget to add another overloaded operator==
for ***All*** its Base classes.
2)We can try using RTTI and we can try checking type at runtime:
bool operator==(const B& b)const
{
if(typeid(*this)==typeid(b))
return /*compare members*/;
else
return false;
}
BUT still we will have to much of unnecessary code to write as when we
define "operator==" for the "Derived" class we can't call
"BaseClass::operator==(oChild)" as we will receive "false" (see above:
expression typeid(BaseClass)==typeid(ChildClass) will alwayse return
false). Unfortunatly no *****_cast operator will help us.
The problem is: what is the 3d option that is safe and elegant?
|
Почему в
случае
вызова operator()
для
объекта
дочернего
класса
вызывается
вопреки
всем
правилам
Base::operator()?
Thanks to everyone for their input. I understand that in real life
members like "m_b" or "m_d1" must be at least protected, and I left
them public just for convenience. Sorry for mistypes in my code they
were caused because of my inattentiveness ;p
Multimethods are good, however in Andrew's book the problem was not
resolved. Look at the chapter 11.6.1. The point was to write some
mechanism that would in some way automatically call child operator's==
based on the information that can be gathered on the compile time.
In any case here is the option I have come up with. Bob Hairgrove
suggested just the same idea as I thought of after some time (though
three weeks has passed since I posted this message here) and it is
based on RTTI . So here is the code
class Base{
public:
Base() : m_i(0){}
virtual bool operator==(const Base& Base)const
{
if(typeid(*this) == typeid(Base)){
return (this->m_i == Base.m_i);
}else{
return false;
}
}
protected:
int m_i;
};
class Derived1 : public Base{
public:
Derived1() : m_d1(1){}
bool operator==(const Derived1& Derived1)const
{
if(typeid(*this) == typeid(Derived1)){
//comparing members of Derived1;
//and calling base class operator== in order to proceed with
comparing
//base class members
return (m_d1 == Derived1.m_d1&&
Base::operator ==(Derived1));
}else{
return false;
}
}
protected:
int m_d1;
};
class Derived2 : public Base{
public:
Derived2() : m_d2(2){}
bool operator==(const Derived2& Derived2)const
{
//comparing members of Derived2;
//and calling base class operator== in order to proceed with
comparing
//base class members
if(typeid(*this) == typeid(Derived2)){
return (m_d2 == Derived2.m_d2&&
Base::operator ==(Derived2));
}else{
return false;
}
}
protected:
int m_d2;
};
int main()
{
using namespace std;
Base BaseObject;
Derived1 Der1Object;
Derived2 Der2Object;
Base* pBase1 = &Der1Object;
Base* pBase2 = &Der2Object;
bool Var = ( *pBase1 == *pBase2 );
cout<< "pBase1 == pBase2 : ";
cout<< (Var) <
return 1;
}
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|