Why can't you have a static and an instance member function with the same signature?
1 2 3 4 5
class A
{
void DoThing(){}
staticvoid DoThing(){}
};
1 2 3 4
A a;
a.DoThing(); //can only possibly call the instance member function
A::DoThing(); //can only possibly call the static member function
//Same for pointer-to-member vs function pointer to static func...
It seems perfectly logical, because there is no ambiguity in any cases I can think of. Why does the code give an error?
because the static variable or function is not attached to the object of the class , but class itself . so when you call it by the object of the class it will be ambiguous .
I'm not sure why. If you write &A::DoThing; it can't know which one you mean, but you will have that problem also when there is more than one function with the same name but different signatures.
You can also not have data member with the same name as any member function. I guess they just want to minimize ambiguity.
a.DoThing(); //can only possibly call the instance member function
I don't think that's true. That's a perfectly legal way to call static members as well.
Also...
1 2 3 4 5 6 7 8 9 10
void A::Foo() // member function of A
{
DoThing(); // <- does this call the static or nonstatic version?
A::DoThing(); // <- what about this?
}
int main()
{
somefuncptrtype = &A::Foo; // does this get a pointer to the static or nonstatic?
}
Of course, all of the above are rhetorical questions, as there is no right answer. These ambiguities are likely why this is not allowed.
EDIT:
although I wonder how the function pointer issue is solved for overloaded functions.... interesting....
That's a perfectly legal way to call static members as well.
Now, see, this is one the the things that I think both Java and C++ got wrong. It makes no sense to access a static member from an instance, especially since it has no polymorphic behavior and is equivalent to using the class' name instead. I don't understand why this would work, but you're right, I just tested and it works oddly enough in C++. Guess I need an explanation on this too...
Edit: also, check this out:
1 2 3 4
void DoThing(){}
void DoThing(int){}
typedefvoid (*Sig)();
Sig s (&DoThing);
compiles just fine - so why can't it be the same with member function pointers vs regular function pointers?
Why can't you have a static and an instance member function with the same signature?
The static storage class specifier doesn't "change" the signature of the function, therefore, the signatures are identical as far as the compiler is concerned and is ambiguous.
Can I seen an example? I keep thinking of template<typename T> and using T::Something(), but I'm probably skipping over an important situation where that isn't applicable.
EDIT: And, please, don't say 'macros', unless that is the absolute only case.
Yes it does. Non-static functions take a hidden parameter to act as a "this" pointer within the function. Static functions have no such parameter.
Yes the Non-static function has the implicit 'this' pointer, but it is not a formal argument and only formal arguments are used in function match criteria.
class Parent
{
public:
staticvoid Func(){}
};
class Child : public Parent {};
template<typaname T>
void Foo(T v)
{
v.Func(); // OK
T::Func(); // fails, T=Child and Func is not a member of Child
}
int main()
{
Child c;
Foo(c);
}
clanmjc wrote:
Yes the Non-static function has the implicit 'this' pointer, but it is not a formal arguments and only formal arguments are used in function match criteria.
Ah, okay, I was misunderstanding and thought you were talking about something else. Nevermind.
There is a simple rule in overloading a class methods or a simple function.
You cant overload a function or class method by it's return value or by declaring it as inline or just a normal function or by declaring it as static and none static function. That cant be done. A function cant be overloaded in this way.
What you are doing here is nothing else , but just overloading your DoThing by declaring it once as static and than as none static( that can be done only if there is a differences between the parameters which are taken by the functions). The compiler can not make any differences between your two methods.
may be some thing like
1 2 3 4 5 6
class A
{
void DoThing();
staticvoid DoThing(int i );
};
> The static storage class specifier doesn't "change" the signature of the function
Of course, it does. A static member function of a class has the same signature as a free function.
> Yes the Non-static function has the implicit 'this' pointer, but it is not a formal argument
> and only formal arguments are used in function match criteria.
This is absurd. How is overloading based on the cv-qualifiers allowed?
struct A
{
int non_static_mfun_one( int i ) const { return non_static_mvar_one + i ; }
// these are valid overloads; the parametrs are of different types
// the cv-qualifiers affect the type of the this pointer
// and therefore also affect the type of the member function
int non_static_mfun_two( int i ) { return i += non_static_mvar_two ; }
int non_static_mfun_two( int i ) const { return non_static_mvar_two + i ; }
int non_static_mfun_two( int i ) volatile { return i += non_static_mvar_two ; }
int non_static_mvar_one = 1 ;
int non_static_mvar_two = 2 ;
staticint static_mfun_one( int i ) { return static_mvar_one + i ; }
staticint static_mfun_two( int i ) { return static_mvar_two + i ; }
staticint static_mvar_one ;
staticint static_mvar_two ;
};
int A::static_mvar_one = 10 ;
int A::static_mvar_two = 20 ;
int free_function( int i ) { return i + 6 ; }
int free_variable = 100 ;
int main()
{
int A::*pointer_to_member_var = nullptr ;
int* pointer_to_free_var = nullptr ;
int (A::*pointer_to_member_fun)(int) const = nullptr ;
int (*pointer_to_free_fun)(int) = nullptr ;
pointer_to_member_var = &A::non_static_mvar_one ; // ok
pointer_to_member_var = &A::non_static_mvar_two ; // ok
// pointer_to_member_var = &A::static_mvar_one ; // *** error ***
// pointer_to_member_var = &free_variable ; // *** error ***
pointer_to_free_var = &A::static_mvar_one ; // ok
pointer_to_free_var = &A::static_mvar_two ; // ok
pointer_to_free_var = &free_variable ; // ok
//pointer_to_free_var = &A::non_static_mvar_one ; // *** error ***
pointer_to_member_fun = &A::non_static_mfun_one ; // ok
pointer_to_member_fun = &A::non_static_mfun_two ; // ok
//pointer_to_member_fun = &A::static_mfun_one ; // *** error ***
//pointer_to_member_fun = &free_function ; // *** error ***
pointer_to_free_fun = &A::static_mfun_one ; // ok
pointer_to_free_fun = &free_function ; // ok
//pointer_to_free_fun = &A::non_static_mfun_one ; // *** error ***
int (A::*pointer_to_volatile_member_fun)(int) volatile = nullptr ;
pointer_to_volatile_member_fun = &A::non_static_mfun_two ; // ok
//pointer_to_volatile_member_fun = &A::non_static_mfun_one ; // *** error ***
// the parameter types are different (for the this pointer)
}
> Also the T::StaticMember approach doesn't work if the static member is in a parent class of T:
>
class Parent
{
public:
staticvoid Func(){}
};
class Child : public Parent {};
template<typaname T>
void Foo(T v)
{
v.Func(); // OK
T::Func(); // fails, T=Child and Func is not a member of Child
}
int main()
{
Child c;
Foo(c);
}
Line 13 is OK too; Func is looked up during the second phase of the two-phase name look up.
This would fail though; dependant names are not looked up during the first phase.
1 2 3 4 5 6 7 8 9 10
template< typename T > struct base { staticvoid foo() {} };
template< typename T > struct derived {} ;
int main()
{
derived<int> object ;
derived<int>::foo() ; // *** error *** 'derived<int>' has no member named 'foo'
object.foo() ; // *** error *** 'derived<int>' has no member named 'foo'
}