Calling static member function through object instance

  • Thread starter Joost Ronkes Agerbeek
  • Start date
J

Joost Ronkes Agerbeek

Why is it allowed in C++ to call a static member function of an object
through an instance of that object? Is it just convenience?

tia,
Joost Ronkes Agerbeek
 
J

Janusz Szpilewski

Joost said:
Why is it allowed in C++ to call a static member function of an object
through an instance of that object? Is it just convenience?

Static member functions primarily follow the invocation convention for
member functions. However as they may be invoked without constructing
any object the extra syntax (qualified id) is provided for this case.

Regards,
Janusz
 
J

jeffc

Joost Ronkes Agerbeek said:
Why is it allowed in C++ to call a static member function of an object
through an instance of that object? Is it just convenience?

I think the question might be answered if you asked a different question.
If I were to ask you why it should NOT be allowed, what would you say?
 
J

Joost Ronkes Agerbeek

I think the question might be answered if you asked a different question.
If I were to ask you why it should NOT be allowed, what would you say?
I would say that, were it not allowed, it would always be clear whether a
call was to a static member or a non-static member.

Part of what brought up this question for me was a passage in A Programmer's
Introduction to C# by Eric Gunnerson regarding calls to static methods
(p.66): "This is unlike the C++ behavior where a static member can be
accessed either through the class name or the instance name. In C++, this
leads to some readability problems, as it's sometimes not clear from the
code whether an access is static or through an instance."

By the way, I sent a reply to Janusz, but accidentely sent it to him in
person instead of to the newsgroup. Here is my reply and his reply to that
reply. (I removed the offending button in my newsreader ;-).)

Thanks for your insights.

Joost
Isn't it the other way around? Static member functions operate on the class,
not the object, so you have to write object::static_function() but for
convenience you can also write instance.static_function(). I know C# doesn't
allow invoking a member function on an object instance: you have to use the
class so that it is always clear you are calling a static member function.
This triggered my original question: if there is an explicit reason the
designers of C# don't allow static member invocation through an instance,
then the designers of C++ must also have a reason why they do allow static
member invocation through an instance, but what is it?

Hard to speak in the name of C++ designers, however in the C++ standard
(9.4/2) one may find the following statement:

"A static member s of class X may be referred to using the qualified-id
expression X::s; it is not necessary to use the class member access
syntax. (5.2.5)"

5.2.5 says about . -> type access

Some paragraphs before discuss class member access in general and from
that perspective one may think of static members as a special case
following the general concept as close as possible.
AFAIK static member functions were not present in C++ from the beginning
and were added somewhat later. So they were expected not to introduce
too many changes.

So I think it may be the reason of differences between C++ (and Java I
think) and C#. The first attitude focuses on keeping language concepts
consistent, fitting static member functions in the scope of member
functions and the second keeps clean programming style in mind.

Regards,
Janusz
 
J

jeffc

I would say that, were it not allowed, it would always be clear whether a
call was to a static member or a non-static member.

Part of what brought up this question for me was a passage in A Programmer's
Introduction to C# by Eric Gunnerson regarding calls to static methods
(p.66): "This is unlike the C++ behavior where a static member can be
accessed either through the class name or the instance name. In C++, this
leads to some readability problems, as it's sometimes not clear from the
code whether an access is static or through an instance."

Bjarne Stroustrup wrote a book about the design choices for the C++
language - you might find a definitive answer there. I've thought for about
5 seconds and don't have an idea about a case where that confusion might
cause a problem, but there might well be one.
 
E

E. Robert Tisdale

Joost said:
Why is it allowed in C++ to call a static member function of an object
through an instance of that object? Is it just convenience?

It is *not* allowed.
 
R

Robert Paul Clark

It is allowed. For convenience is probably the best answer.

Example:
#include <iostream>

class A
{
public:
static void foo() { std::cout << "foobar" << std::endl; };
};

int
main()
{
A a;
a.foo();
}

Output: foobar
 
D

Dario

Even the following code works!

#include <cstdio>
class A {
public:
static void foo() { printf("Hello world.\n"); };
};
int main() {
A* a[10];
int i;
for(i=0; i<10; i++)
a = 0;
a[5]->foo();
a[50]->foo();
}
 
K

Karl Heinz Buchegger

Dario said:
Even the following code works!

But *this* code is illegal.
#include <cstdio>
class A {
public:
static void foo() { printf("Hello world.\n"); };
};
int main() {
A* a[10];
int i;
for(i=0; i<10; i++)
a = 0;
a[5]->foo();
a[50]->foo();


you are dereferencing a 0-pointer.
And this is always a no-no, even if
your specific system does *not* crash.
 
D

Dario

Karl said:
Dario said:
Even the following code works!


But *this* code is illegal.

#include <cstdio>
class A {
public:
static void foo() { printf("Hello world.\n"); };
};
int main() {
A* a[10];
int i;
for(i=0; i<10; i++)
a = 0;
a[5]->foo();
a[50]->foo();



you are dereferencing a 0-pointer.
And this is always a no-no, even if
your specific system does *not* crash.


No !

When I evaluate
a[5]->foo()
a[5] is 0 but this does not matter
because foo is a static member;
a[50]->foo()
a[50] is whatever but this does not matter
because foo is a static member.

So my program is legal and works for every C++ compiler.

- Dario
 
K

Karl Heinz Buchegger

Dario said:

Yes.
Read your code.
When I evaluate
a[5]->foo()
a[5] is 0 but this does not matter
because foo is a static member;
a[50]->foo()
a[50] is whatever but this does not matter
because foo is a static member.

So my program is legal and works for every C++ compiler.

It is not legal, read the standard.
It doesn't matter if your compiler doesn't need
to dereference the pointer to call this function
under the hood. Your source code contains the
dereference and hence it is an illegal program.
 
J

Jerry Coffin

[ ... ]
you are dereferencing a 0-pointer.
And this is always a no-no, even if
your specific system does *not* crash.

No !

When I evaluate
a[5]->foo()
a[5] is 0 but this does not matter
because foo is a static member;

This is utterly irrelevant -- 5.2.5/1 says "the expression before the
dot or arrow is evaluated". Footnote 58 explicitly states that "This
evaluation happens even if the result is unnecessary to determine the
value of the entire postfix expression, for example if the id-expression
denotes a static member."

As such, you're assured that this dereferences a null pointer, which
gives undefined behavior.
So my program is legal and works for every C++ compiler.

Your program contains undefined behavior. If your definition of
"works" includes the possibility of crashing the computer, reformatting
the hard drive or making demons fly out of your nose, then you're right:
it works for every C++ compiler. Anybody who has a stricter definition
of work will want to avoid this construct.
 
A

Andy Buchanan

Bjarne Stroustrup wrote a book about the design choices for the C++
language - you might find a definitive answer there. I've thought for about
5 seconds and don't have an idea about a case where that confusion might
cause a problem, but there might well be one.

It caught me out (shockingly recently), somehow I managed to miss the
whole call via instance mechanism for the 8+ years I've used c++, I
always used the :: form and I never saw anyone else do otherwise....

class BlahBlah
{
public:
BlahBlah& Instance(); // some sort of singleton i/f

private:
static void Eot( Client* client, int flags, void* uopt )
{
// Mistaken assumption: overload resolution calls
// the non-static member ( due to implicit 'this' )
// Actual behaviour: Recursive call & hang!
Instance().Eot( client, flags, uopt );
}
void Eot( Client* client, int flags, void* uopt );
};

In case you're wondering this was just code to interface
to a 3rd party C lib that used callbacks (yuk). Usually I would have
had different names for the two Eot() functions, but not this
time for some reason.

I would have thought the compiler might have determined
the Eot call to be amibiguous, but it didn't ( Compiler was a gcc
2.95.x derivitive.). Does a static member function rate higher
than an ordinary member function in overload resolution?
 
B

Bjarne Stroustrup

The reason for allowing p->static_member_function(); is exactly not to
require a user to remember if a function is static or not. Why should
the user care, except in the case where he/she wants to call without
an object?

It caught me out (shockingly recently), somehow I managed to miss the
whole call via instance mechanism for the 8+ years I've used c++, I
always used the :: form and I never saw anyone else do otherwise....

class BlahBlah
{
public:
BlahBlah& Instance(); // some sort of singleton i/f

private:
static void Eot( Client* client, int flags, void* uopt )
{
// Mistaken assumption: overload resolution calls
// the non-static member ( due to implicit 'this' )
// Actual behaviour: Recursive call & hang!
Instance().Eot( client, flags, uopt );
}
void Eot( Client* client, int flags, void* uopt );
};

In case you're wondering this was just code to interface
to a 3rd party C lib that used callbacks (yuk). Usually I would have
had different names for the two Eot() functions, but not this
time for some reason.

I would have thought the compiler might have determined
the Eot call to be amibiguous, but it didn't ( Compiler was a gcc
2.95.x derivitive.). Does a static member function rate higher
than an ordinary member function in overload resolution?

No. That declaration is illegal. From the standard:

"[class.static.mfct] 9.4.1 Static member functions

There shall not be a static and a nonstatic member function with the
same name
and the same parameter types (13.1)."

This has always been the rule. Without that rule, people could get
into all kinds of nasty problems.

It is always most anoying when a compiler fails to implement a clear
and simple language rule.

- Bjarne Stroustrup; http://www.research.att.com/~bs
 
O

Old Wolf

When I evaluate
a[5]->foo()
a[5] is 0 but this does not matter
because foo is a static member;

This is utterly irrelevant -- 5.2.5/1 says "the expression before the
dot or arrow is evaluated". Footnote 58 explicitly states that "This
evaluation happens even if the result is unnecessary to determine the
value of the entire postfix expression, for example if the id-expression
denotes a static member."

As such, you're assured that this dereferences a null pointer, which
gives undefined behavior.

Your quote is irrelevant. "the expression before the dot or arrow"
is "a[5]". This is easy to evaluate: 0
You will have to look elsewhere in the Standard to find a definitive
answer.
Next question: what is the difference, if any, between:
a[5]->foo()
(*a[5]).foo()
 
A

Andy Buchanan

Andy Buchanan <[email protected]> wrote in message news:<[email protected]>...
It caught me out (shockingly recently), somehow I managed to miss the
whole call via instance mechanism for the 8+ years I've used c++, I
always used the :: form and I never saw anyone else do otherwise....

class BlahBlah
{
public:
BlahBlah& Instance(); // some sort of singleton i/f

private:
static void Eot( Client* client, int flags, void* uopt )
{
// Mistaken assumption: overload resolution calls
// the non-static member ( due to implicit 'this' )
// Actual behaviour: Recursive call & hang!
Instance().Eot( client, flags, uopt );
}
void Eot( Client* client, int flags, void* uopt );
};

In case you're wondering this was just code to interface
to a 3rd party C lib that used callbacks (yuk). Usually I would have
had different names for the two Eot() functions, but not this
time for some reason.

I would have thought the compiler might have determined
the Eot call to be amibiguous, but it didn't ( Compiler was a gcc
2.95.x derivitive.). Does a static member function rate higher
than an ordinary member function in overload resolution?

No. That declaration is illegal. From the standard:

"[class.static.mfct] 9.4.1 Static member functions

There shall not be a static and a nonstatic member function with the
same name
and the same parameter types (13.1)."

This has always been the rule. Without that rule, people could get
into all kinds of nasty problems.

As indeed I did. I shant be making this mistake again even if the
compiler lets me. Thanks for the pointer.
It is always most anoying when a compiler fails to implement a clear
and simple language rule.

Alas the compiler in question has allowed a number of other
incorrect constructs. As a further alas, I'm pretty much stuck with
 
J

Joost Ronkes Agerbeek

Bjarne Stroustrup said:
The reason for allowing p->static_member_function(); is exactly not to
require a user to remember if a function is static or not. Why should
the user care, except in the case where he/she wants to call without
an object?

Thanks for the answer!

The C# design team thinks the user cares because it makes their code more
readable. I'm not partial to either view, I was merely curious.

Joost Ronkes Agerbeek
 
H

Hendrik Schober

Bjarne Stroustrup said:
[...]
The reason for allowing p->static_member_function(); is exactly not to
require a user to remember if a function is static or not. Why should
the user care, except in the case where he/she wants to call without
an object?

For the same reason the users should care
about whether a member function is 'const'
or not: One will not change the object it
is called for while the other one might.
The only way to find out about this now
is from looking at the signature -- which
is not really all that bad. However, _if_
only the special syntax for static member
functions was allowed, it would be easier
to avoid that Murphy guy.


Schobi

--
(e-mail address removed) is never read
I'm Schobi at suespammers dot org

"Sometimes compilers are so much more reasonable than people."
Scott Meyers
 
B

Bjarne Stroustrup

Hendrik Schober said:
Bjarne Stroustrup said:
[...]
The reason for allowing p->static_member_function(); is exactly not to
require a user to remember if a function is static or not. Why should
the user care, except in the case where he/she wants to call without
an object?

For the same reason the users should care
about whether a member function is 'const'
or not: One will not change the object it
is called for while the other one might.
The only way to find out about this now
is from looking at the signature -- which
is not really all that bad. However, _if_
only the special syntax for static member
functions was allowed, it would be easier
to avoid that Murphy guy.

Would you also like the language prohibit calls of const member
functions for non-const objects? The general idea is to allow safe
operations, such as invoking const member functions on non-const
objects and static member functions for an object, while disallowing
potentially damaging ones, such as invoking a non-const member
function for a const object or a non-static member function without an
object.

I don't think Murphy enters into this.
 
B

Bjarne Stroustrup

Andy Buchanan said:
Alas the compiler in question has allowed a number of other
incorrect constructs. As a further alas, I'm pretty much stuck with
it for the rest of the project (and probably the next). <sigh>

For what it's worth, gcc 3.3.2 doesn't have that problem.
 

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
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top