tags:

views:

2948

answers:

10

I have a helper class that is just a bunch of static methods and would like to subclass the helper class. Some behavior is unique depending on the subclass so I would like to call a virtual method from the base class, but since all the methods are static I can't create a plain virtual method (need object reference in order to access virtual method).

Is there any way around this? I guess I could use a singleton.. HelperClass.Instance.HelperMethod() isn't so much worse than HelperClass.HelperMethod(). Brownie points for anyone that can point out some languages that support virtual static methods.

Edit: OK yeah I'm crazy. Google search results had me thinking I wasn't for a bit there.

+13  A: 

Virtual static methods don't make sense. If I call HelperClass.HelperMethod();, why would I expect some random subclass' method to be called? The solution really breaks down when you have 2 subclasses of HelperClass - which one would you use?

If you want to have overrideable static-type methods you should probably go with:

  • A singleton, if you want the same subclass to be used globally.
  • A tradition class hierarchy, with a factory or dependency injection, if you want different behavior in different parts of your application.

Choose whichever solution makes more sense in your situation.

Chris Marasti-Georg
-1 Because you forgot about generics. T.Add(leftT, rightT); has so much sense. Isn't it?
SeeR
And how would you override your implementation in a subclass?
Chris Marasti-Georg
It could be implemented as a virtual instance member of the class' type. Subclasses' types would inherit from the class' type, allowing them to override.
Strilanc
Yes, but the subclass' implementation would not be available from the base type in a static context, which is what the original question asked.
Chris Marasti-Georg
+3  A: 

a static method exists outside of an instance of a class. It cannot use any non-static data.

a virtual method will be "overwritten" by an overloaded function depending of the type of an instance.

so you have a clear contradiction between static and virtual.

This is not a problem of support, It is a concept. So I doubt you will find any OOP-Language which will support virtual static methods.

Peter Parker
A virtual method can be overwritten on the type of the instance. All subclasses can share the same implementation of the overloaded function. That's why you want to make them BOTH static and virtual. That's late static binding, available in PHP5.
Alex
No, there is no contradiction, it is entirely a matter of compiler support, and many languages like Python do it. They do it by having first-class classes. That is, classes that are themselves objects that can be assigned to variables and have their methods called. (Search for "classmethod" to learn more.)
Daniel Newby
+1  A: 

I heard that Delphi suports something like this. It seems it does it by making classes object instances of a metaclass.

I've not seen it work, so I'm not sure that it works, or what's the point for that.

P.S. Please correct me if I'm wrong, since it's not my domain.

rslite
+2  A: 

Indeed, this can be done in Delphi. An example:

type
  TForm1 = class(TForm)
    procedure FormShow(Sender: TObject);
  end;

  TTestClass = class
  public
    class procedure TestMethod(); virtual;
  end;

  TTestDerivedClass = class(TTestClass)
  public
    class procedure TestMethod(); override;
  end;

  TTestMetaClass = class of TTestClass;

var
  Form1: TForm1;

implementation

{$R *.dfm}

class procedure TTestClass.TestMethod();
begin
  Application.MessageBox('base', 'Message');
end;

class procedure TTestDerivedClass.TestMethod();
begin
  Application.MessageBox('descendant', 'Message');
end;


procedure TForm1.FormShow(Sender: TObject);
var
  sample: TTestMetaClass;
begin
  sample := TTestClass;
  sample.TestMethod;
  sample := TTestDerivedClass;
  sample.TestMethod;
end;

Quite interesting. I no longer use Delphi, but I recall being able to very easily create different types of controls on a custom designer canvas using the metaclass feature: the control class, eg. TButton, TTextBox etc. was a parameter, and I could call the appropriate constructor using the actual metaclass argument.

Kind of the poor man's factory pattern :)

Alan
A: 

Because a virtual method uses the defined type of the instantiated object to determine which implementation to execute, (as opposed to the declared type of the reference variable)

... and static, of course, is all about not caring if there's even an instantiated instance of the class at all...

So these are incompatible.

Bottom line, is if you want to change behavior based on which subclass an instance is, then the methods should have been virtual methods on the base class, not static methods.

But, as you already have these static methods, and now need to override them, you can solve your problem by this: Add virtual instance methods to the base class that simply delegate to the static methods, and then override those virtual instance wrapper methods (not the static ones) in each derived subclass, as appropriate...

charles bretana
A: 

You are not crazy. What you are referring to is called Late Static Binding; it's been recently added to PHP. There's a great thread that describes it - here: http://stackoverflow.com/questions/87192/when-would-you-need-to-use-late-static-binding#87351

Alex
A: 

It is actually possible to combine virtual and static for a method or a member by using the keyword new instead of virtual.

Here is an example:

class Car
{
    public static int TyreCount = 4;
    public virtual int GetTyreCount() { return TyreCount; }
}
class Tricar : Car
{
    public static new int TyreCount = 3;
    public override int GetTyreCount() { return TyreCount; }
}

...

Car[] cc = new Car[] { new Tricar(), new Car() };
int t0 = cc[0].GetTyreCount(); // t0 == 3
int t1 = cc[1].GetTyreCount(); // t1 == 4

Obviously the TyreCount value could have been set in the overridden GetTyreCount method, but this avoids duplicating the value. It is possible to get the value both from the class and the class instance.

Now can someone find a really intelligent usage of that feature?

Mart
@Mart: I almost downvoted you until I realized you've just got a bad example. Instead of the static fields, change the example to use static methods, where the derived class calls the base class method, then does something more.
John Saunders
A: 

I don't think you are crazy. You just want to use what is impossible currently in .NET.

Your request for virtual static method would have so much sense if we are talking about generics. For example my future request for CLR designers is to allow me to write intereface like this:

public interface ISumable<T>
{
  static T Add(T left, T right);
}

and use it like this:

public T Aggregate<T>(T left, T right) where T : ISumable<T>
{
  return T.Add(left, right);
}

But it's impossible right now, so I'm doing it like this:

    public static class Static<T> where T : new()
    {
      public static Value = new T();
    }

    public interface ISumable<T>
    {
      T Add(T left, T right);
    }

    public T Aggregate<T>(T left, T right) where T : ISumable<T>, new()
    {
      return Static<T>.Value.Add(left, right);
    }
SeeR
@SeeR: -1: I'll correct that if I'm wrong, but this doesn't solve the original problem.
John Saunders
@John Saunders: He want static virtual methods, but it's impossible - He must use instance methods for it. He also don't want to instantiate this class everytime he want to use this static (now instance) methods - this is why I created Static<T> class. Now he will only have only one instance of his class for the whole application. I think it's acceptable tax for such functionality. Aggregate<T> method is just an example how he can use it. So in summary we have static virtual replacement in c# - wasn't that the request in question?
SeeR
A: 

I don't understand the "accepted" answer on here. As stated, your argument against static virtual methods would also be an argument against normal virtual methods, wouldn't it?

It seems the asker would want a static virtual method not to do HelperClass.HelperMethod() but to do DerivedHelperClass.HelperMethod. In this case, any "random" static virtual methods being called are not random at all, but the ones defined in DerivedHelperClass. The same idea behind non-static virtual methods.

It is, of course, very possible I'm missing something.

Jeff
@Jeff: you can already have a static `DerivedHelperClass.HelperMethod()`. If you call it that way, the derived version will be called. If you call `HelperClass.HelperMethod()` then the base class version will be called. What the OP didn't apparently understand is that `virtual` allows you to call a `virtual` method defined in the base class through a reference to the base class, and to get the derived class version. But this only makes sense for an instance, i.e., not a static method.
John Saunders
A: 

I come from Delphi and this is a feature among many that I sorely miss in c#. Delphi would allow you to create typed type references and you could pass the type of a derived class wherever the type of a parent class was needed. This treatment of types as objects had powerful utility. In particular allowing run time determination of meta data. I am horribly mixing syntax here but in c# it would look something like:

    class Root {
       public static virtual string TestMethod() {return "Root"; }
    }
    TRootClass = class of TRoot; // Here is the typed type declaration

    class Derived : Root {
       public static overide string TestMethod(){ return "derived"; }
    }

   class Test {
        public static string Run(){
           TRootClass rc;
           rc = Root;
           Test(rc);
           rc = Derived();
           Test(rc);
        }
        public static Test(TRootClass AClass){
           string str = AClass.TestMethod();
           Console.WriteLine(str);
        }
    } 

would produce: Root derived

Ken Revak