Thread overview | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
October 08, 2004 Why can't static functions be virtual | ||||
---|---|---|---|---|
| ||||
Why can't static functions be virtual? Wouldn't it be nice to be able to create functions like Java's java.awt.ToolKit.getDefaultToolkit which can be overridden by a subclass to return a single instance of a certain class ? |
October 09, 2004 Re: Why can't static functions be virtual | ||||
---|---|---|---|---|
| ||||
Posted in reply to Grinny | Grinny wrote: > Why can't static functions be virtual? Wouldn't it be nice to be able to create > functions like Java's java.awt.ToolKit.getDefaultToolkit which can be > overridden by a subclass to return a single instance of a certain class ? > > In Java, static functions are *NOT* virtual. Simply because it is not needed. If you want to use java.awt.ToolKit.getDefaultToolkit() you are refering to the ToolKit class. If you decide to inherit the ToolKit class, and make a new getDefaultToolkit() function, you need to perform another upcall like com.company.YourToolKit.getDefaultToolkit(). This function does not override the original function. Regards, Sjoerd |
January 16, 2007 Re: Why can't static functions be virtual | ||||
---|---|---|---|---|
| ||||
Posted in reply to Grinny | I was going to ask why they weren't virtual. I wrote this: class CBase { static void hello() { printf("hello from CBase\n"); } } class CDerived : CBase { static void hello() { printf("hello from CDerived\n"); } } void main() { CDerived derived = new CDerived; CBase base = derived; base.hello(); // prints Hello from CBase void function() fn; fn = &CDerived.hello; fn =&base.hello; // compiler error } Are statics non-virtual because that's the way c++ does it? Surely the compiler can see base.hello() and then: * look up the CBase class definition to find hello * get its index in the vtable and note that it is static * dereference base to get the CDerived vtable * get the address that corresponds to hello * call hello without passing base as a secret this pointer Its the same sequence of steps as for a non-static virtual. The only difference is that you don't pass base as a hidden parameter. The difference is how parameters are passed on the stack. Then when the compiler sees: fn = &base.hello; It does the same vtable lookup and assigns the found address to fn because statics don't need the 'secret this pointer'. I expected that &base.hello would be equivalent to &CDerived.hello and that &derived.CBase.hello would be equivalent to &CBase.hello just as derived.CBase.hello() prints "Hello from CBase" Anyway, the question is: why doesn't D do this? Why the distinction between static members and non-static members? |
January 17, 2007 Re: Why can't static functions be virtual | ||||
---|---|---|---|---|
| ||||
Posted in reply to John McAuley | I suppose it does it this way because every other statically typed language I know of does it this way. And they do it because, AFAIK, it makes sense to. The method you are calling isn't attached to the instance at all--it's attached to the class itself. When you say "base.hello()", the compiler's actually cutting you some slack and saying "well, I know what you *really* mean, so I'll let you off" and calls the method. class Foo { static void bar() { ... } } is pretty much the same as void Foo_bar() { with(Foo) { ... } } Which means that "base" has absolutely nothing to do with looking up the method whatsoever (well, apart from what the container type is). Look at it like this: static methods don't HAVE a vtable; they're just methods that sit somewhere in memory that just happen to be related to a certain class. There's simply no mechanism for looking up derived versions at runtime. So yeah; this same thing caught me once or twice when I first started with C++, but I've honestly never been able to come up with a compelling reason to do it any other way. -- Daniel |
January 17, 2007 Re: Why can't static functions be virtual | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Keep | Simply put, static functions don't have a 'this' pointer, so it's impossible to make a static function a virtual function. Objects with virtual functions have a 'hidden ID' which sets a unique value for each class type (AFAIK anyways...). If you don't have the 'this' pointer, you can't read the hidden ID in the object, so you don't know what type the object is, making it impossible to know which virtual function to call. |
January 17, 2007 Re: Why can't static functions be virtual | ||||
---|---|---|---|---|
| ||||
Posted in reply to Xinok | Xinok wrote:
> Simply put, static functions don't have a 'this' pointer, so it's impossible to make a static function a virtual function.
> Objects with virtual functions have a 'hidden ID' which sets a unique value for each class type (AFAIK anyways...). If you don't have the 'this' pointer, you can't read the hidden ID in the object, so you don't know what type the object is, making it impossible to know which virtual function to call.
I think there is a usage case for a function that acts virtual when called with an object instance, but static when called with just the class name.
It almost seems like you should be able to achieve it by just defining two versions of the method:
foo() { ... }
static foo() { ... }
If you think of the non-static version as having a hidden 'this' parameter, those two are not ambiguous according to standard overloading rules.
On the other hand, you can pretty easily just make two versions of the function to achieve much the same thing, and just have the virtual version call the static version.
static Foo() {}
foo() { Foo(); }
Then if you have an object instance you can call inst.foo() and otherwise you can call Klass.Foo().
--bb
|
January 17, 2007 Re: Why can't static functions be virtual | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bill Baxter | Bill Baxter Wrote: > I think there is a usage case for a function that acts virtual when called with an object instance, but static when called with just the class name. > Definitely. > It almost seems like you should be able to achieve it by just defining two versions of the method: > > foo() { ... } > static foo() { ... } > > If you think of the non-static version as having a hidden 'this' parameter, those two are not ambiguous according to standard overloading rules. > > On the other hand, you can pretty easily just make two versions of the function to achieve much the same thing, and just have the virtual version call the static version. > > static Foo() {} > foo() { Foo(); } > > Then if you have an object instance you can call inst.foo() and otherwise you can call Klass.Foo(). > > --bb I've done something similar in c++ class CFoo : public CBase { public: static const wchar_t *StaticTag() { static const wchar_t tag[] = L"foo"; return tag; } static CBase *StaticCreate() { return new CFoo; } virtual const wchar_t *VirtualTag() { return StaticTag(); } virtual CBase VirtualCreate() { return StaticCreate(); } } I was reading xml and creating a tree of objects with the aid of a factory that had an STL map that mapped string to object creator. You would register with the factory using: pFactory->Register(CFoo::StaticTag(), CFoo::StaticCreator); I had a GUI that made new nodes like this: CFoo *pFoo = CFoo::StaticCreator(); So far we are using statics, but when I want to write the tree back to xml I need virtuals. void WriteXml(CBase *pRoot) { printf("<%s>\n", pRoot->VirtualTag()); // foreach child of pRoot { WriteXml(child); } printf("<\\%s>\n", pRoot->VirtualTag()); } It worked but I had about 30 node types in a single schema and I had several schemas. I don't like the extra baggage of declaring separate static and virtual versions just because the language doesn't have virtual statics. (Evil C style macros to the rescue :-) ) |
January 17, 2007 Re: Why can't static functions be virtual | ||||
---|---|---|---|---|
| ||||
Posted in reply to Xinok | Xinok Wrote:
> Simply put, static functions don't have a 'this' pointer, so it's impossible to make a static function a virtual function.
> Objects with virtual functions have a 'hidden ID' which sets a unique value for each class type (AFAIK anyways...). If you don't have the 'this' pointer, you can't read the hidden ID in the object, so you don't know what type the object is, making it impossible to know which virtual function to call.
That doesn't sound right.
For example:
CBase *baseRef = new CDerived;
baseRef.hello(); // hello is a virtual static
I HAVE an object reference/pointer, its baseRef.
The compiler knows the definition of the CBase class. So it knows the vtable offset and the fact that hello is static.
The compiler can emit code that dereferences baseRef to get the CDerived vtable, gets the function address and calls it without passing baseRef as the 'hidden this pointer'. The code calls the func as a static member and not as an instance member.
Voila! virtual static call.
Have I missed something? Should I slink away all embarrassed? :-)
|
January 17, 2007 Re: Why can't static functions be virtual | ||||
---|---|---|---|---|
| ||||
Posted in reply to John McAuley | John McAuley wrote:
> Bill Baxter Wrote:
>
>
>> I think there is a usage case for a function that acts virtual when called with an object instance, but static when called with just the class name.
>>
>
> Definitely.
>
>> It almost seems like you should be able to achieve it by just defining two versions of the method:
>>
>> foo() { ... }
>> static foo() { ... }
>>
>> If you think of the non-static version as having a hidden 'this' parameter, those two are not ambiguous according to standard overloading rules.
>>
>> On the other hand, you can pretty easily just make two versions of the function to achieve much the same thing, and just have the virtual version call the static version.
>>
>> static Foo() {}
>> foo() { Foo(); }
>>
>> Then if you have an object instance you can call inst.foo() and otherwise you can call Klass.Foo().
>>
>> --bb
>
> I've done something similar in c++
>
> class CFoo : public CBase
> {
> public:
> static const wchar_t *StaticTag()
> {
> static const wchar_t tag[] = L"foo";
> return tag;
> }
> static CBase *StaticCreate()
> {
> return new CFoo;
> }
>
> virtual const wchar_t *VirtualTag() { return StaticTag(); }
> virtual CBase VirtualCreate() { return StaticCreate(); }
> }
>
> I was reading xml and creating a tree of objects with the aid of a factory that had an STL map that mapped string to object creator.
>
> You would register with the factory using:
> pFactory->Register(CFoo::StaticTag(), CFoo::StaticCreator);
>
> I had a GUI that made new nodes like this:
>
> CFoo *pFoo = CFoo::StaticCreator();
>
> So far we are using statics, but when I want to write the tree back to xml I need virtuals.
>
> void WriteXml(CBase *pRoot)
> {
> printf("<%s>\n", pRoot->VirtualTag());
>
> // foreach child of pRoot
> {
> WriteXml(child);
> }
>
> printf("<\\%s>\n", pRoot->VirtualTag());
> }
>
> It worked but I had about 30 node types in a single schema and I had several schemas. I don't like the extra baggage of declaring separate static and virtual versions just because the language doesn't have virtual statics. (Evil C style macros to the rescue :-) )
Seems like it should be possible for the compiler to realize when you're not using 'this' in a method and create the vtable entry for the function sans hidden 'this' parameter. Then it could make such a function callable via either Class.method or instance.method syntax.
--bb
|
January 17, 2007 Re: Why can't static functions be virtual | ||||
---|---|---|---|---|
| ||||
Posted in reply to John McAuley | John McAuley wrote:
> Xinok Wrote:
>
>> Simply put, static functions don't have a 'this' pointer, so it's impossible to make a static function a virtual function.
>> Objects with virtual functions have a 'hidden ID' which sets a unique value for each class type (AFAIK anyways...). If you don't have the 'this' pointer, you can't read the hidden ID in the object, so you don't know what type the object is, making it impossible to know which virtual function to call.
>
> That doesn't sound right.
>
> For example:
>
> CBase *baseRef = new CDerived;
>
> baseRef.hello(); // hello is a virtual static
>
> I HAVE an object reference/pointer, its baseRef.
>
> The compiler knows the definition of the CBase class. So it knows the vtable offset and the fact that hello is static.
>
> The compiler can emit code that dereferences baseRef to get the CDerived vtable, gets the function address and calls it without passing baseRef as the 'hidden this pointer'. The code calls the func as a static member and not as an instance member.
>
> Voila! virtual static call.
>
> Have I missed something? Should I slink away all embarrassed? :-)
>
The problem is that static methods generally don't have offsets in the vtable at all, so getting the CDerived vtable doesn't help.
--bb
|
Copyright © 1999-2021 by the D Language Foundation