Computer Chess Club Archives


Search

Terms

Messages

Subject: Re: Is there an overhead in this OO design ?

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.