Concatenating Calls

F

foodic

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

thanks
divya
 
G

Gianni Mariani

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;}

setX returns void !
void setY(int y) {_y = y;}

So does setY.
void doubleMe()
{
_x *= 2;
_y *= 2;
}
private:
int _x;
int _y;
};
int main(){
SetMe lower;
((lower.setX(20)).setY(30)).doubleMe();

Here you use the return value from setX (which is void) and call setY.


You probably want to do this.

SetMe & setX(int x) {_x = x; return *this;}
SetMe & setY(int y) {_y = y; return *this;}
SetMe * doubleMe() { .... return *this;}
}
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

Return the object by reference.
 
K

Karl Heinz Buchegger

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.
 
A

Aslan Kral

"Karl Heinz Buchegger" <[email protected]>, haber iletisinde sunlari
yazdi:[email protected]...

lower.setX( 20 ).setY( 30 );


You can even begin with the class contructor like this:

SetMe().setX( 20 ).setY( 30 );
// if you don't need "lower" after this line of course,
// say passing it finally into a function as a parameter.
 
R

Ron Natalie

Aslan said:
You can even begin with the class contructor like this:

SetMe().setX( 20 ).setY( 30 );

That's not a constructor. You can't call constructors nor do
they return a value.
 
A

Aslan Kral

haber iletisinde sunlari said:
That's not a constructor. You can't call constructors nor do
they return a value.
What do you call it then? And how does it work on my pc? (See beloew)

class SetMe {
public:
SetMe()
{
printf("SetMe constructor\n");
}
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;
};

int main()
{
printf("Before -- SetMe constructor\n");
SetMe().setX(1).setY(2);
printf("After -- SetMe constructor\n");
return 0;
}

Output:
Before -- SetMe constructor
SetMe constructor
After -- SetMe constructor
 
M

Michael Etscheid

Ron said:
That's not a constructor. You can't call constructors

I can call constructors, although indirectly. Look at this:

---------->8---------->8----------
class Foo
{
Foo(int) {}
};

int main()
{
Foo(10); // constructor call
}
---------->8---------->8----------
nor do they return a value.

ISO-IEC 14882-1998 §12.1.12:

"No return type (not even void) shall be specified for a constructor. A
return statement in the body of a constructor shall not specify a return
value. The address of a constructor shall not be taken."

There is not written that a constructor doesn't have a return type.
Please correct me if it's written at another place.
 
H

Howard

Michael Etscheid said:
I can call constructors, although indirectly. Look at this:

---------->8---------->8----------
class Foo
{
Foo(int) {}
};

int main()
{
Foo(10); // constructor call
}
---------->8---------->8----------


ISO-IEC 14882-1998 '12.1.12:

"No return type (not even void) shall be specified for a constructor. A
return statement in the body of a constructor shall not specify a return
value. The address of a constructor shall not be taken."

There is not written that a constructor doesn't have a return type. Please
correct me if it's written at another place.

It looks like it says there is no return type pretty clearly, at least to
me. It says "No return type..shall be specified". That means that it does
not have a return type. How can you have a return type if you don't specify
what the type _is_? It also says it "shall not specify a return value".
That means that nothing _can_ be returned! In other words, if you have a
return statement in the constructor, it hsa to stand alone, as in "return;",
instead of specifying a return value as in "return 0;". So, if a
constructor does not specify a return type, and does not return a value, how
can you say it "has" a return type? I'd like to see an example of a
constructor that _does_ have a return type!

By the way, your example does not actually "call" the constructor. When you
write the statement "Foo(10);", you're creating an unnamed temporary
variable. The creation of that temporary does involve calling that
constructor, but technically you're not doing so yourself. (Which, I
suppose, is why you stated "although indirectly" above.)

-Howard
 
R

Ron Natalie

Michael said:
Foo(10); // constructor call
correct me if it's written at another place.

That's not a constructor call. Constructors don't have names,
they don't participate in name look up. The syntax you have above
is actually an "explicit conversion (functional notation)" according
to the language syntax.

What it does is convert 10 to type Foo (creating a temporary in
the process). The creation of this temporary involves allocation
of sizeof (FOO) bytes of memory and then initializing it by calling
the Foo(int) constructor.

It's impossible for user code to call constructors, they can only
create objects in ways that the implmentation invokes the constructors
for them.
 
G

Gianni Mariani

Ron said:
Michael Etscheid wrote: ....


It's impossible for user code to call constructors, they can only
create objects in ways that the implmentation invokes the constructors
for them.

Except for placement new. This is essentially a constructor call (not
in the strict C++ sense).
 
M

Michael Etscheid

Howard said:
It looks like it says there is no return type pretty clearly, at least to
me. It says "No return type..shall be specified". That means that it does
not have a return type. How can you have a return type if you don't specify
what the type _is_? It also says it "shall not specify a return value".
That means that nothing _can_ be returned!

Or it says that the return type is specified and unchangable. I don't
know that with that text.
By the way, your example does not actually "call" the constructor. When you
write the statement "Foo(10);", you're creating an unnamed temporary
variable. The creation of that temporary does involve calling that
constructor, but technically you're not doing so yourself. (Which, I
suppose, is why you stated "although indirectly" above.)

Right.
 
M

Michael Etscheid

Ron said:
That's not a constructor call. [...]
and then initializing it by calling
the Foo(int) constructor.

It's impossible for user code to call constructors, they can only
create objects in ways that the implmentation invokes the constructors
for them.

That's why I wrote indirectly.
 
K

Karl Heinz Buchegger

Gianni said:
Except for placement new. This is essentially a constructor call (not
in the strict C++ sense).

But even then, the C++ standard says about it:
It creates an object
 
K

Karl Heinz Buchegger

Aslan said:
And calling the constructor as a result. Does it matter to call it John or
Mary?

Yes, it does.

The C++ programmer cannot directly call a constructor (for good reasons).
The constructor is no ordinary function, it doesn't participate in function
name lookup. Thus it is impossible to call it.

But one can create an object in various ways. Part of that object construction
is that the constructor gets called. That's a subtle different thing and answers
a question that comes up frequently: "How can I call a constructor from inside
another constructor? Why doesn't it work the way I do it?"
 
A

Aslan Kral

haber iletisinde sunlari said:
Yes, it does.

The C++ programmer cannot directly call a constructor (for good reasons).
The constructor is no ordinary function, it doesn't participate in function
name lookup. Thus it is impossible to call it.

I didn't say you can call a constructor directly. I should have said
"indirectly" which I didn't and you assumed I meant "directly".

My point was to show that entire program could just be one line as an
example of "Concatenating Calls" starting with object creation at the
beginning (so constructor called *indirectly*).

class X
{
int i;
public:
X(int i_){ i=i_; }
X& M1(int i) { ++i; return *this; }
int M2(int i) { return --i; }
};

int main()
{
return X(1).M1(2).M2(3);
}
 
K

Karl Heinz Buchegger

Aslan said:
I didn't say you can call a constructor directly. I should have said
"indirectly" which I didn't and you assumed I meant "directly".
I think all of the regulars understood what you ment.
Nevertheless, all I can say is: Watch your language!
We are mostly dealing with newbies, so using a proper
nomenclature is important.
My point was to show that entire program could just be one line as an
example of "Concatenating Calls" starting with object creation at the
beginning (so constructor called *indirectly*).

So why didn't you say so in the beginning:

You can even begin with creating a temporary object like so:
SetMe().setX( 20 ).setY( 30 );

and nobody would have objected to anything.
 

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

Members online

No members online now.

Forum statistics

Threads
474,202
Messages
2,571,057
Members
47,660
Latest member
vidotip479

Latest Threads

Top