function calls

P

Paul

Is an nonstatic member function call the same as an ordinary function call
(with a hidden parameter)?
Two people , namely James Kanze and Itaj Sherman have been trying to
persuade me that a call to a nonstatic member function is exactly the same
as an ordinary function call.
I disagree with them because I think the C++ standard disagrees with them.
Does anyone have any views on this?
I wonder if either of them would like to clarify exactly what they mean, or
exactly what they are trying to say so that we may debate the issue
properly.
 
P

Paul

5.2.2 Function call [expr.call]
1 There are two kinds of function call: ordinary function call and member
function54) (9.3) call. A function
call is a postfix expression followed by parentheses containing a possibly
empty, commaseparated
list of
expressions which constitute the arguments to the function. For an ordinary
function call, the postfix
expression shall be either an lvalue that refers to a function (in which
case the functiontopointer
standard
conversion (4.3) is suppressed on the postfix expression), or it shall have
pointer to function type. Calling a
__________________
53) This is true even if the subscript operator is used in the following
common idiom: &x[0].
54) A static member function (9.4) is an ordinary function.
 
M

Martijn van Buul

* Paul:
Is an nonstatic member function call the same as an ordinary function call
(with a hidden parameter)?

Yes, as long as the nonstatic member function isn't virtual. There are some
differences between the two at compile time, (which you could describe as
'syntactic sugar') but pedantics asside, the difference between

class SomeClass
{
[...]
public:
int SomeFunction(int argument);
}

and

class SomeClass
{
[...]
public:
static int (SomeClass *my_this, int argument);
}

is rather thin in practice: In case of the member function, 'this' is implicit,
and access to members are implicitly through 'this'. (hence the 'syntactic
sugar') In case of the static function, they're both made explicit - but
that's about it.

To my best knowledge this doesn't contradict the standard at all.
 
B

Branimir Maksimovic

Is an nonstatic member function call the same as an ordinary function
call (with a hidden parameter)?
Two people , namely James Kanze and Itaj Sherman have been trying to
persuade me that a call to a nonstatic member function is exactly the
same as an ordinary function call.
I disagree with them because I think the C++ standard disagrees with
them. Does anyone have any views on this?

I won;t talk about standard definition as syntactically calls are
different. Semantically, there is difference for virtual member
function call vs ordinary function call.
 
P

Paul

Martijn van Buul said:
* Paul:

Yes, as long as the nonstatic member function isn't virtual. There are
some
differences between the two at compile time, (which you could describe as
'syntactic sugar') but pedantics asside, the difference between

If you sorta skip over the compilation process and directly access a
functions' machine code does the function have full access to the objects
private members? Also the pointer passed as *this may not necessarilly point
to an object of the class-type(that declares the member function)/or
derived class-type.

class SomeClass
{
[...]
public:
int SomeFunction(int argument);
}

and

class SomeClass
{
[...]
public:
static int (SomeClass *my_this, int argument);
}

is rather thin in practice: In case of the member function, 'this' is
implicit,
and access to members are implicitly through 'this'. (hence the 'syntactic
sugar') In case of the static function, they're both made explicit - but
that's about it.

To my best knowledge this doesn't contradict the standard at all.
I'm not sure how a 'this' pointer( a pointer to an object) can be associated
with a static member function. A static is not associated with any object,
its same as a normal function but its in class scope.

What do you think would happen if you tried to compile some code that
dereferenced *this inside a static member function, I don't think you'd get
it through any compiler but I'm not sure. I might try it later on today.

TY for your post.
Paul.
 
P

Paul

Branimir Maksimovic said:
I won;t talk about standard definition as syntactically calls are
different. I Agree.
Semantically, there is difference for virtual member
function call vs ordinary function call.
Do you think this is always the case with the calling mechanics for any
given implementation, or do you have a specific platform in mind? ( i.e :
x86, A64).

I think the OS also has an influence on this, in cases where you invoke a
DLL member function, or some other OS specific object.

I think its not so simple as some suggest, always good to hear the views of
others .
Thx for your post
Paul.
 
B

Branimir Maksimovic

Do you think this is always the case with the calling mechanics for
any given implementation, or do you have a specific platform in mind?
( i.e : x86, A64).
This is the case for any given implementation.
No matter implementation, virtual function calls are dynamic dispatch
when type is not known at compile time.
 
J

James Kanze

Is an nonstatic member function call the same as an ordinary function call
(with a hidden parameter)?
Two people , namely James Kanze and Itaj Sherman have been trying to
persuade me that a call to a nonstatic member function is exactly the same
as an ordinary function call.

Not exactly the same, but fundamentally the same.
I disagree with them because I think the C++ standard disagrees with them..

The C++ standard does specify significant differences in the
calling syntax (e.g. in §5.2.2). Beyond that, however, it
requires the this pointer to be initialized exactly as if it
were a reference to an object (except that it is initialized
with pointer type, and not with reference type). And it
certainly treats them the same in overload resolution. There's
no fundamental difference between them.

There are other subtle differences: a non-const member function
can be called on a temporary, where as a non-const reference
cannot be initialized with a temporary, for example. But in the
other thread, you were looking for things that would make
member functions fundamentally different from non-members.
Where as I fail to see anything but syntax differences between
titi and tata in the following:

struct Toto
{
void titi() const;
friend void tata(Toto const&);
};

This is, of course, an extreme case of similarity. But my point
is that except for syntax, member functions have a series of
characteristics that can, in specific cases, apply to non member
functions as well.
 
P

Paul

Is an nonstatic member function call the same as an ordinary function call
(with a hidden parameter)?
Two people , namely James Kanze and Itaj Sherman have been trying to
persuade me that a call to a nonstatic member function is exactly the same
as an ordinary function call.

--Not exactly the same, but fundamentally the same.

Ah ok sorry misunderstanding.
I disagree with them because I think the C++ standard disagrees with them.

--The C++ standard does specify significant differences in the
--calling syntax (e.g. in §5.2.2).
Ok so this is the syntaxical rules we must obey, is it not?
-- Beyond that, however, it
--requires the this pointer to be initialized exactly as if it
--were a reference to an object (except that it is initialized
--with pointer type, and not with reference type). And it
--certainly treats them the same in overload resolution. There's
--no fundamental difference between them.

Now I find what you say here slightly confusing.
You say "beyond that" which I take to mean ..Beyond the definition of the
standard, in your previous sentence.
Then you go on about what the standard requires for initialisation of the
this pointer.
Surely we must either speak in terms of the standard or not, you seem to
jump in and out of standards context when it suits you.

But ignoring that, what you actually speak about is initialisation of the
this pointer, which I presume is a pointer, yes?
You seem to intepret the this pointer a reference, surely the this pointer
is not required to be converted to a refernece, this seems like an
unneccessarry converion forced upon a compiler i.e :
pointer -> reference -> pointer. (why?)

Don't get me wrong I understand what you are saying about the underlying
mechanics of a nonvirtual function call, but the issue here is:
Are we allowed to do this as per the C++ std, which is the general concensus
of this group to determine proper C++ code.


--There are other subtle differences: a non-const member function
--can be called on a temporary, where as a non-const reference
--cannot be initialized with a temporary, for example.
I see again you introduce references , this obviously has seem to be a
requirement for you argument.
I don't see the need to have any references when calling a member function,
therefore this continued use of referneces in your demonstrations leads me
to believe there is something wrong.
Can you not give an example using simple pointers ?

-- But in the
--other thread, you were looking for things that would make
--member functions fundamentally different from non-members.

I'm not looking for something to make them different , I know they are
different. I'm trying to understand why you think it's beneficial to think
of them as the the same.
One word proves they're different ...virtual.
But I realise you are talking about non virtual and I don't try to be
awkward by suggesting this , I am simply pointing out the onus is not on me
to prove a difference.

As below we must respectively assume you are obviously not talking about
virtual functions

--Where as I fail to see anything but syntax differences between
--titi and tata in the following:
-- struct Toto
-- {
-- void titi() const;
-- friend void tata(Toto const&);
-- };
--This is, of course, an extreme case of similarity. But my point
--is that except for syntax, member functions have a series of
--characteristics that can, in specific cases, apply to non member
--functions as well.

Yes I agree.

But that syntax difference means we are not allowed to do the following, or
does it:

struct ObjT{
void mthd(){};
};

ObjT o;
mthd(o); /*I do not understand this is uncharted waters to me*/
mthd(&o) /*or is this what you propose?its not a reference I know*/
o.mthd() /*my normal calling syntax*/

I don't know if any of the above is proper code I didn't try to compile
anything, please can you explain what is valid as per the standard.
 
Ö

Öö Tiib

--  But in the
--other thread, you were looking for things that would make
--member functions fundamentally different from non-members.

I'm not looking for something to make them different , I know they are
different. I'm trying to understand why you think it's beneficial to think
of them as the the same.

But they are logically same. For example when i see two lines of code:

bag1.sort();
sort( bag2 );

Should i think that different things happened to bag1 and bag2? Nope.
I only think that both objects got sorted, only that sorting
functionality was delivered syntactically differently by interface of
their classes. Also i see nothing why to call one of them OOP and
other non-OOP.

Now if to think about flexibility of interface ... then in C++ i
actually don't even know exactly whose member function was called in
first line and if there was a function called at all in second line.
Maybe first line called operator()() of public data member of bag1
named "sort" and second line maybe constructed temporary of type
"sort".
 
P

Paul

-- But in the
--other thread, you were looking for things that would make
--member functions fundamentally different from non-members.

I'm not looking for something to make them different , I know they are
different. I'm trying to understand why you think it's beneficial to think
of them as the the same.

--But they are logically same. For example when i see two lines of code:

-- bag1.sort();
-- sort( bag2 );

--Should i think that different things happened to bag1 and bag2? Nope.
--I only think that both objects got sorted, only that sorting
--functionality was delivered syntactically differently by interface of
--their classes. Also i see nothing why to call one of them OOP and
--other non-OOP.

The obvious difference in the above is:
bag1.sort() /*sort is a member function of bag 1*/
sort(bag2) /*sort is not a memeber function*/

Inside the member function we have access to the this pointer. The term
"this" suggests an object identity. The following does not work:
void sort(){
overwrite the object 'this' points to; (with _thiscall: mov ecx, 0 would do
it)
call thisfunction; /*'this' == ?? */
}

Normal sort() does not have a this pointer , there is no similar object
identity. Within normal sort() the object passed as a parameter has no
control over the lifetime of the function.
The following applies for the normal sort() function:
void sort(anObject){
overwrite anObject ;
call thisfunction(anObject) ; /* anObject is OK, it contains what we
overwrit it with*/
}


Your post is presented well (in a way that makes one think about it).


--Now if to think about flexibility of interface ... then in C++ i
--actually don't even know exactly whose member function was called in
--first line and if there was a function called at all in second line.

Yep because it could be an constructor (still a function I guess but I'm
with ya I think)

--Maybe first line called operator()() of public data member of bag1
--named "sort"
This loses me I'm afraid, I will need to think some more on this.

-- and second line maybe constructed temporary of type
--"sort".
Yep as I commented above I see that.

Alot of this has to do with OO design I think.
Ty for your post.
Paul.
 
Ö

Öö Tiib

--Maybe first line called operator()() of public data member of bag1
--named "sort"
This loses me I'm afraid, I will need to think some more on this.

I meant like that:

struct A
{
void operator()() { }
};

struct B
{
A sort;
};

int main()
{
B bag1;
bag1.sort();
}
 
P

Paul

--Maybe first line called operator()() of public data member of bag1
--named "sort"
This loses me I'm afraid, I will need to think some more on this.

--I meant like that:
--struct A { void operator()() { } };
--struct B { A sort; };

-- int main(){
-- B bag1;
-- bag1.sort();
-- }
Oh yes, I understand this.
But I'm not sure about the point you were making about the flexibility of
the interfase.
 
P

Paul

Paul said:
--But they are logically same. For example when i see two lines of code:

-- bag1.sort();
-- sort( bag2 );

--Should i think that different things happened to bag1 and bag2? Nope.
--I only think that both objects got sorted, only that sorting
--functionality was delivered syntactically differently by interface of
--their classes. Also i see nothing why to call one of them OOP and
--other non-OOP.

The obvious difference in the above is:
bag1.sort() /*sort is a member function of bag 1*/
sort(bag2) /*sort is not a memeber function*/

Inside the member function we have access to the this pointer. The term
"this" suggests an object identity. The following does not work:
void sort(){
overwrite the object 'this' points to; (with _thiscall: mov ecx, 0 would
do it)
call thisfunction; /*'this' == ?? */
}

Normal sort() does not have a this pointer , there is no similar object
identity. Within normal sort() the object passed as a parameter has no
control over the lifetime of the function.
The following applies for the normal sort() function:
void sort(anObject){
overwrite anObject ;
call thisfunction(anObject) ; /* anObject is OK, it contains what we
overwrit it with*/
}
You did not comment on this, do you understand what I am explaining?

<snip>
 
Ö

Öö Tiib

You did not comment on this, do you understand what I am explaining?

Yes, i understand. For me both the functions are part of A's
interface:

void A::eek:neOperation() {/* code operating on this */}
void otherOperation( A& that ) {/* code operating on that */}

What is the big matter if there is pointer "this" or reference "that"?
The otherOperation() is even more OOP for me since it accesses only
public interface of class A and does not mess with dirty inner
details. So i know that if i for some performance reasons have to
refactor implementation details of A leaving its public interface same
then i don't need to modify otherOperation (or tests written for it).
 
P

Paul

You did not comment on this, do you understand what I am explaining?

--Yes, i understand. For me both the functions are part of A's
--interface:
--void A::eek:neOperation() {/* code operating on this */}
--void otherOperation( A& that ) {/* code operating on that */}

--What is the big matter if there is pointer "this" or reference "that"?
--The otherOperation() is even more OOP for me since it accesses only
--public interface of class A and does not mess with dirty inner
--details. So i know that if i for some performance reasons have to
--refactor implementation details of A leaving its public interface same
--then i don't need to modify otherOperation (or tests written for it).

Forgetting about operator oveloading , I am talking about what sort()
initially seemed to be proposed as, specifically:
anObj.sort(); /*A member function of anObject*/
sort(anObj) /*A normal function with 'this' passed explicitly as a
parameter*/

The difference is the possible sequences of execution given the following
scenario of recursion.

sort(){
this = new anObjType; /*replace the object the function belongs to*/
(*this).sort(); /*re-invoke this function is not possible, what does
'this' point to?*/
}

sort(anObj){
anObj = new anObjTye; /*replacing the object( heap or stack whatever,
the code is psuedo)*/
pointertothisfunction(anObj) /*Ok to call this function, recursion is ok
with a new object.*/
}


The member function version does not have the same possible sequences of
execution as the normal version.
The member function version has an object identity, it belongs to the object
on which it is called.

I hope I have explained well.

TY
Paul.
 
R

Rolf Magnus

Paul said:
Forgetting about operator oveloading , I am talking about what sort()
initially seemed to be proposed as, specifically:
anObj.sort(); /*A member function of anObject*/
sort(anObj) /*A normal function with 'this' passed explicitly as a
parameter*/

The difference is the possible sequences of execution given the following
scenario of recursion.

sort(){
this = new anObjType; /*replace the object the function belongs to*/

You can't change the this pointer. It is constant, so the compiler will bail
out with an error at this point.
(*this).sort(); /*re-invoke this function is not possible, what does
'this' point to?*/
}

sort(anObj){
anObj = new anObjTye; /*replacing the object( heap or stack whatever,
the code is psuedo)*/
pointertothisfunction(anObj) /*Ok to call this function, recursion is
ok
with a new object.*/
}


The member function version does not have the same possible sequences of
execution as the normal version.
The member function version has an object identity, it belongs to the
object on which it is called.

Within the member function, the this-pointer is const, and so you can't
assign to it. If you declare your non-member function as:

sort(sometype* const anObj)

you'll have the same problem as with the member function.
 
P

Paul

Rolf Magnus said:
You can't change the this pointer. It is constant, so the compiler will
bail
out with an error at this point.

This is psuedo code, you can change the object 'this' points to using any
code you like, obviously that's assuming the object is not stored in
read-only memoery.
Sorry I should've made a specific note about psuedo code. I presumed it was
obvious following from the context of my previous example.
Within the member function, the this-pointer is const, and so you can't
assign to it. If you declare your non-member function as:

sort(sometype* const anObj)

you'll have the same problem as with the member function.
The constantness is not rellevant to understand the point as code can be
written to overcome that.
Neither the stack nor the heap is read only. The object 'this' points to is
likely to be in one of these areas, therefore overwriteable.

Ty for reading
Paul.
 
P

Paul

The member function version does not have the same possible sequences of
execution as the normal version.
It means the member function stops but the normal function is recursive.

The member function version has an object identity,?
It means each function invokation is attached to a unique object
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top