Author: Gerd Isenberg
Date: 11:21:28 01/06/06
Go up one level in this thread
On January 06, 2006 at 13:08:20, Alexander Kure wrote:
>On January 06, 2006 at 11:54:27, Gerd Isenberg wrote:
>
>>>>But doesn't hiding the implementation for this scalar wrapper class - without
>>>>any virtuals - also imply that it don't cares whether a public interface is used
>>>>internally but also privat members?
>>>
>>>Sorry Gerd, I don't quite understand your question.
>>>Can you try to rephrase it?
>>>
>>>Best,
>>>Alex
>>
>>If isAdjacent is a const member or friend, it has read access to
>>private/proteceted members - but is not forced to do so - it may also use the
>>public interface only. If so, should that be a reason to make the function not
>>member or friend?
>
>This depends. If there is a performance issue that can be solved by having
>access to the internal data representation of a class you should make this
>function a member of that class.
>Compare this to map member function std::map::find() and the algorithm
>std::find(). The first one has O(log(n)) logarithmic time by making use of the
>internal binary tree representation in the map class while the algorithm takes
>O(n) linear time for lookup.
>On the other side if you can implement a function by using a classes public
>interface only then make this function a non-member function. Thus you also
>decrease the dependency of clients to the public interface of that class.
>Clients don't have to recompile because you want to add a new convenient
>function to your class. Encapsulation and decoupling!
I see.
>
>>Making a function a member of a class or not - should imho not only depend on
>>its access rights, but also on the semantic and logical relations of the
>>function.
>
>No. It should depend on encapsulation and decoupling issues.
Ok.
>
>>I mean with some point and rectangle classes - i found it so far somehow natural
>>or at least familiar to have the boolean isPointInRect as member of a rectangle.
>
>Good point. This function should not be part of the interface of the rectangle
>class. IsPointInRect() is just a different concept. Making it part of the class
>increases coupling of different concepts in one class.
Seems i am biased by using mfc too much ;-)
>
>Another point:
>Consider the standard C++ complex class.
>Only operator+=() is defined as member function, but operator+() is not.
>Why is this so? Encapsulation! You can implement operator+() outside the complex
>class by just using complex' member function operator+=()
Aha, very interesting. I had following in mind:
Combined assignment operators or members like increment/decrement modify *this,
which is already an existing object, refered as r- and l-value. So it is very
"natural" to make those functions members of the class. Returning *this, thus a
reference of this object: T& operator+=(const T &op).
Binary operators like T friend operator+(const T &op1, const T &op2) don't have
an existing object yet, but have to create one on the fly for the result.
>
>complex operator(const complex& lhs, const complex& rhs)
>{
> complex temp = lhs;
> temp += rhs; // calls temp.operator+=(rhs);
> return(temp);
>}
Ok, i begin to understand.
In my xmm-wrapper i still have disjoint implementations of eg. operator&= and
operator&. It would be fine to have all binary operators in the base class,
using the combined assignment operators of the derived classes. But i can not
make pure virtual operator&= here, because of register incarnations of objects!?
class DBB
{
friend class XMM;
friend class GPR;
public:
DBB(){}
DBB(const BitBoard &l, const BitBoard &h) {s[0] = l; s[1] = h;}
...
protected:
union
{
__m128i x; // this intrinsice type is wrapped here
BitBoard s[2];
};
};
class XMM : public DBB
{
public:
XMM(){}
XMM(const DBB& a){x = a.x;}
XMM(__m128i a){x = a;}
...
XMM& operator&=(const XMM &a) {
x = _mm_and_si128(x, a.x);
return *this;
}
friend XMM operator& (const XMM &a, const XMM &b) {
return XMM(_mm_and_si128(a.x, b.x));
}
...
};
class GPR : public DBB
{
public:
GPR(){}
GPR(const BitBoard &l, const BitBoard &h) {s[0] = l; s[1] = h;}
GPR(const DBB& a) {s[0] = a.s[0]; s[1] = a.s[1];}
...
GPR& operator&=(const GPR &a) {
s[0]&=a.s[0]; s[1]&=a.s[1];
return *this;
}
friend GPR operator&(const GPR &a, const GPR &b) {
return GPR(a.s[0]&b.s[0], a.s[1]&b.s[1]);
}
...
};
....
// possible application:
// pass either MMX or GPR as template type
template <class T>
void leAttacks(sTarget* pTarget, const sSource* pSource)
{
T gl(pSource->rooks);
T pl(pSource->occup);
pl = (~pl).notH();
gl |= pl & (gl>>1);
pl &= pl>>1;
gl |= pl & (gl>>2);
pl &= pl>>2;
gl |= pl & (gl>>4);
(gl>>1).notH().store(&pTarget->le);
}
...
void rookAttacks(sTarget* pTarget, const sSource* pSource)
{
riAttacks<XMM>(pTarget, pSource);
leAttacks<GPR>(pTarget, pSource);
upAttacks<XMM>(pTarget, pSource);
dnAttacks<GPR>(pTarget, pSource);
}
>
>>May be my autodidactical oo-knowledge needs some lifting ;-)
>
>I recommend reading Scott Meyers' excellent book "Effectiv C++", Addison Wesley,
>3rd edition.
Thanks,
Gerd
This page took 0 seconds to execute
Last modified: Thu, 15 Apr 21 08:11:13 -0700
Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.