views:

814

answers:

9

Is it possible in C++ to have a member function that is both static and virtual? Apperantly, there isn't a straight-forward way to do it (static virtual member(); is a complie error), but at least a way to acheive the same effect?

I.E:

struct Object
{
     struct TypeInformation;

     static virtual const TypeInformation &GetTypeInformation() const;
};

struct SomeObject : public Object
{
     static virtual const TypeInformation &GetTypeInformation() const;
};

It makes sence to use GetTypeInformation() both on an instance (object->GetTypeInformation()) and on a class (SomeObject::GetTypeInformation()), which can be useful for comparsions and vital for templates.

The only ways I can think of involves writing two functions / a function and a constant, per class, or use macros.

Any other solutions?

+13  A: 

No, there's no way to do it, since what would happen when you called Object::GetTypeInformation()? It can't know which derived class version to call since there's no object associated with it.

You'll have to make it a non-static virtual function to work properly; if you also want to be able to call a specific derived class's version non-virtually without an object instance, you'll have to provide a second redunduant static non-virtual version as well.

Adam Rosenfield
+4  A: 

No, this is not possible, because static member functions lack a this pointer. And static members (both functions and variables) are not really class members per-se. They just happen to be invoked by ClassName::member, and adhere to the class access specifiers. Their storage is defined somewhere outside the class; storage is not created each time you instantiated an object of the class. Pointers to class members are special in semantics and syntax. A pointer to a static member is a normal pointer in all regards.

virtual functions in a class needs the this pointer, and is very coupled to the class, hence they can't be static.

Mads Elvheim
A: 

No, its not possible, since static members are bound at compile time, while virtual members are bound at runtime.

Visage
A: 

I ran into this problem the other day: I had some classes full of static methods but I wanted to use inheritance and virtual methods and reduce code repetition. My solution was to use a singleton instance pattern: each class contains a static method that you call to get a pointer to a single, shared instance of the class. You can make the constructors private or protected so that outside code can't misuse it by creating additional instances.

Nate C-K
A: 

Like other's have said, there are 2 important pieces of information.

1) There is no this pointer when making a static fn call and

2) The this pointer points to the structure where the virtual table, or thunk, are used to look up which runtime method to call.

So a static function is determined at compile time.

I showed this code example in: http://stackoverflow.com/questions/1640309/c-static-members-in-class/1640619#1640619

That shows that you can call a static method on a NULL pointer.

struct Foo
{
    static int boo() { return 2; }
};

int _tmain(int argc, _TCHAR* argv[])
{
    Foo* pFoo = NULL;
    int b = pFoo->boo(); // b will now have the value 2
    return 0;
}
chollida
Technically, this is undefined behavior. You cannot deference a null pointer for any reason. The only things that you can do with a null pointer is a) assign another pointer to it and b) compare it with another pointer.
KeithB
Furthermore, you can only compare it _for equality_ (or inequality_ with another pointer, not ordering. I.e. `p < null`, `p >= null` etc are all undefined as well.
Pavel Minaev
@KeithB - For completeness you can also safely call delete on a null pointer.
Steve Rowe
+7  A: 

Many say it is not possible, I would go one step further and say it is not meaningfull.

A static member is something that does not relate to any instance, only to the class.

A virtual member is something that does not relate directly to any class, only to an instance.

So a static virtual member would be something that does not relate to any instance or any class.

Rasmus Kaj
It is perfectly meaningful in languages where classes are first-class values - e.g. Delphi has that, and also has "static virtual" methods.
Pavel Minaev
Not really - rememeber that in those systems, classes are values themselves, of a single type. At best, their type (class) is derived from a basic 'basetype', and their sibling types would be unions, built-ins, etc. A virtual method is shared across all instances of a single type; thus the virtual methods associated with the "class" type would be shared across all classes.
MSalters
+2  A: 

It is possible. Make two functions: static and virtual

struct Object{     
  struct TypeInformation;
  static  const TypeInformation &GetTypeInformationStatic() const 
  { 
      return GetTypeInformationMain1();
  }
  virtual const TypeInformation &GetTypeInformation() const
  { 
      return GetTypeInformationMain1();
  }
protected:
  static const TypeInformation &GetTypeInformationMain1(); // Main function
};

struct SomeObject : public Object {     
  static  const TypeInformation &GetTypeInformationStatic() const 
  { 
      return GetTypeInformationMain2();
  }
  virtual const TypeInformation &GetTypeInformation() const
  { 
      return GetTypeInformationMain2();
  }
protected:
  static const TypeInformation &GetTypeInformationMain2(); // Main function
};
Alexey Malistov
You're trying to access a non-static member from a static function, which is not possible.
mxp
Right. I fixed.
Alexey Malistov
Also, static methods cannot be const. It just does not make sense, what instance are they not going to mutate?
David Rodríguez - dribeas
Mmmm. Right. I fixed again.
Alexey Malistov
+1  A: 

I think what you're trying to do can be done through templates. I'm trying to read between the lines here. What you're trying to do is call a method from some code, where it calls a derived version but the caller doesn't specify which class. Example:

class Foo {
pubic:
    void M() {...}
};

class Bar : public Foo {
pubic:
    void M() {...}
};

void Try()
{
    xxx::M();
}

int main()
{
    Try();
}

You want Try() to call the Bar version of M without specifying Bar. The way you do that for statics is to use a template. So change it like so:

class Foo {
pubic:
    void M() {...}
};

class Bar {
pubic:
    void M() {...}
};

template <class T>
void Try()
{
    T::M();
}

int main()
{
    Try<Bar>();
}
zumalifeguard
If you indent your code 4 spaces you can get it automatically formatted. Alternatively I believe you can use the back tick to achieve the same purpose inline.
chollida
+1  A: 

It is possible!

But what exactly is possible, let's narrow down. People often want some kind of "static virtual function" because of duplication of code needed for being able to call the same function through static call "SomeDerivedClass::myfunction()" and polymorphic call "base_class_pointer->myfunction()". "Legal" method for allowing such functionality is duplication of function definitions:

class Object
{
public:
    static string getTypeInformationStatic() { return "base class";}
    virtual string getTypeInformation() { return getTypeInformationStatic(); }
}; 
class Foo: public Object
{
public:
    static string getTypeInformationStatic() { return "derived class";}
    virtual string getTypeInformation() { return getTypeInformationStatic(); }
};

What if base class has a great number of static functions and derived class has to override every of them and one forgot to provide a duplicating definition for virtual function. Right, we'll get some strange error during runtime which is hard to track down. Cause duplication of code is a bad thing. The following tries to resolve this problem (and I want to tell beforehand that it is completely type-safe and doesn't contain any black magic like typeid's or dynamic_cast's :)

So, we want to provide only one definition of getTypeInformation() per derived class and it is obvious that it has to be a definition of static function because it is not possible to call "SomeDerivedClass::getTypeInformation()" if getTypeInformation() is virtual. How can we call static function of derived class through pointer to base class? It is not possible with vtable because vtable stores pointers only to virtual functions and since we decided not to use virtual functions, we cannot modify vtable for our benefit. Then, to be able to access static function for derived class through pointer to base class we have to store somehow the type of an object within its base class. One approach is to make base class templatized using "curiously recurring template pattern" but it is not appropriate here and we'll use a technique called "type erasure":

class TypeKeeper
{
public:
    virtual string getTypeInformation() = 0;
};
template<class T>
class TypeKeeperImpl: public TypeKeeper
{
public:
    virtual string getTypeInformation() { return T::getTypeInformationStatic(); }
};

Now we can store the type of an object within base class "Object" with a variable "keeper":

class Object
{
public:
    Object(){}
    boost::scoped_ptr<TypeKeeper> keeper;

    //not virtual
    string getTypeInformation() const 
    { return keeper? keeper->getTypeInformation(): string("base class"); }

};

In a derived class keeper must be initialized during construction:

class Foo: public Object
{
public:
    Foo() { keeper.reset(new TypeKeeperImpl<Foo>()); }
    //note the name of the function
    static string getTypeInformationStatic() 
    { return "class for proving static virtual functions concept"; }
};

Let's add syntactic sugar:

template<class T>
void override_static_functions(T* t)
{ t->keeper.reset(new TypeKeeperImpl<T>()); }
#define OVERRIDE_STATIC_FUNCTIONS override_static_functions(this)

Now declarations of descendants look like:

class Foo: public Object
{
public:
    Foo() { OVERRIDE_STATIC_FUNCTIONS; }
    static string getTypeInformationStatic() 
    { return "class for proving static virtual functions concept"; }
};

class Bar: public Foo
{
public:
    Bar() { OVERRIDE_STATIC_FUNCTIONS; }
    static string getTypeInformationStatic() 
    { return "another class for the same reason"; }
};

usage:

Object* obj = new Foo();
cout << obj->getTypeInformation() << endl;  //calls Foo::getTypeInformationStatic()
obj = new Bar();
cout << obj->getTypeInformation() << endl;  //calls Bar::getTypeInformationStatic()
Foo* foo = new Bar();
cout << foo->getTypeInformation() << endl; //calls Bar::getTypeInformationStatic()
Foo::getTypeInformation(); //compile-time error
Foo::getTypeInformationStatic(); //calls Foo::getTypeInformationStatic()
Bar::getTypeInformationStatic(); //calls Bar::getTypeInformationStatic()

Advantages:

  1. less duplication of code (but we have to call OVERRIDE_STATIC_FUNCTIONS in every constructor)

Disadvantages:

  1. OVERRIDE_STATIC_FUNCTIONS in every constructor
  2. memory and performance overhead

Open issues:

1) there are different names for static and virtual functions how to solve ambiguity here?

class Foo
{
public:
    static void f(bool f=true) { cout << "static";}
    virtual void f() { cout << "virtual";}
};
//somewhere
Foo::f(); //calls static f(), no ambiguity
ptr_to_foo->f(); //ambiguity

2) how to implicitly call OVERRIDE_STATIC_FUNCTIONS inside every constructor?

Alsk