foodic said:
i am fresher to C++ programming, and I just
want to learn Concatenating Calls, I have
written a program,
class SetMe {
public:
void setX(int x) {_x = x;}
void setY(int y) {_y = y;}
void doubleMe()
{
_x *= 2;
_y *= 2;
}
private:
int _x;
int _y;
};
int main(){
SetMe lower;
((lower.setX(20)).setY(30)).doubleMe();
}
While compiling on gcc version 3.2.3 on Redhat Linux
it gives following errors,
point.c: In function `int main()':
point.c:17: request for member `setY' in
`(&lower)->SetMe::setX(int)(20)', which is of non-aggregate type
`void'
Would somebody explain how to remove this error.
I want to retain the style of concatenating calls
The keypoint in this is, that each function has to return something
that the next call can act on.
If you want to do
SetMe lower;
lower.setX( 20 ).setY(30);
then the part
lower.setX( 20 )
must evaluate to something that is usable as object such
that setY can work on. Best you start with
SetMe lower;
SetMe someObj;
someObj.setY( 30 );
now replace someObj with lower.setX( 20 )
lower.setX( 20 ).setY( 20 );
from this it is clear that the expression "lower.SetX( 20 )" must
have the same type as someObj before. Thus SetX must return a SetMe
object. (For obvious reasons I do the same modification on SetX,
SetY and doubleMe simultanously)
(Note: the following is not quite what you want, but close.
I come back to it in a minute)
class SetMe
{
public:
SetMe setX(int x) { _x = x; return *this; }
SetMe setY(int y) { _y = y; return *this; }
SetMe doubleMe()
{
_x *= 2;
_y *= 2;
return *this;
}
private:
int _x;
int _y;
};
Now every function returns a SetMe object. Thus when
lower.SetX( 20 )
is evaluated, its result is a SetMe object, which can be
used for the next call:
lower.setX( 20 ).doubleMe().setY( 30 );
But wait: What is the exact return type of each function?
It is 'SetMe'. That means that for every return a copy
of the object that was worked on is returned. Thus in the
above the object for which doubleMe is called, is *not*
lower, but is an object which is an exact copy of lower right
after the call to SetX has finished. If this is not what you
want, then the return type needs some slight modification.
What we want is not a copy of the object, but the object itself.
We do this by returning a reference to the object:
class SetMe
{
public:
SetMe& setX(int x) { _x = x; return *this; }
SetMe& setY(int y) { _y = y; return *this; }
SetMe& doubleMe()
{
_x *= 2;
_y *= 2;
return *this;
}
private:
int _x;
int _y;
};
Now the returned object of setX is the very same object that
was used for the call to setX ( 'this' is the C++ way to say
'I' or 'me'. The only thing is that 'this' is a pointer type.
So to say 'return me' you have to dereference the pointer, hence
return *this; )
In
lower.setX( 20 ).setY( 30 );
the call to setX now returns a reference to the object it was
called with, which was 'lower'. Thus setY will again work on 'lower'
and do its work.
That's the whole secret.