40

In C++ is not possible to declare a static virtual function, neither cast a non-static function to a C style function pointer.

Now, I have a plain ol' C SDK that uses function pointers heavily.

I have to fill a structure with several function pointers. I was planning to use an abstract class with a bunch of static pure virtual methods, and redefine them in derived classes and fill the structure with them. It wasn't until then that I realized that static virtual are not allowed in C++.

Also this C SDKs function signature doesn't have a userData param.

Is there any good alternative? The best I can think of is defining some pure virtual methods GetFuncA(), GetFuncB(),... and some static members FuncA()/FuncB() in each derived class, which would be returned by the GetFuncX(). Then a function in the abstract class would call those functions to get the pointers and fill the structure.

Edit Answering to John Dibling, it would be great to be able to do this:

class Base
{
    FillPointers() { myStruct.funA = myFunA; myStruct.funB = myFunB; ...}
private:
    CStruct myStruct;
    static virtual myFunA(...) = 0;
    static virtual myFunB(...) = 0;
};

class Derived1 : public Base
{
    Derived1() {  FillPointers();  }
    static virtual myFunA(...) {...};
    static virtual myFunB(...) {...};
};

class Derived2 : public Base
{
    Derived2() {  FillPointers();  }
    static virtual myFunA(...) {...};
    static virtual myFunB(...) {...};
};

int main()
{
    Derived1 d1;
    Derived2 d2;
    // Now I have two objects with different functionality
}
Georg Fritzsche
  • 97,545
  • 26
  • 194
  • 236
raven
  • 2,574
  • 2
  • 27
  • 49
  • 11
    There's a good reason static virtual functions are not allowed. If you have a class that contains pure virtual functions it becomes abstract. An abstract class cannot be instantiated, so there's no risk of those functions being called. However, if you allow static virtuals, they could potentially be called from the class with out instantiating it. There would be nothing to prevent them from being called before they were defined! – Daniel Bingham Apr 27 '10 at 14:10
  • 18
    The idea of a `static` function is directly opposed to the idea of a pure `virtual` function. Perhaps if you explained what you were trying to achieve rather than how you were trying to achieve it, we might give you better guidance. – John Dibling Apr 27 '10 at 14:11
  • Does the C SDK pass a context pointer to the functions? Alternatively do you only need to have one handler active at a time? – Georg Fritzsche Apr 27 '10 at 14:15
  • @Jamie: Can you post some code that you would *like* to write, but can't because there's no such thing as a `static virtual`? – John Dibling Apr 27 '10 at 14:26
  • 1
    Simple: initialize the pointers in the derived classes' CTors. It's not really so much of extra code. – peterchen Apr 27 '10 at 14:45
  • @Jamie: I don't get it. What you've posted is just plain ol' virtual functions. Remove the `static` keyword and all should be fine. I'm missing why you think you need `static`? – John Dibling Apr 27 '10 at 15:09
  • FillPointers() { myStruct.funA = myFunA; myStruct.funB = myFunB; ...} This won't compile unless myFunA and myfunB are static. – raven Apr 27 '10 at 15:14
  • @John Dibling - the virtual methods are expected to be called by C code. C can't call C++ virtual methods, but it can call static methods. – Ori Pessach Apr 27 '10 at 15:28
  • Solved. Someone posted something about CRTP but before I managed to carefully read it I updated the page and it was deleted. However the wikipedia gave me the missing details. Now I wonder what answer should I accept -_- – raven Apr 27 '10 at 15:37
  • Post an answer with a link to the Wikipedia article on CRTP and accept your own answer if you feel that's the best one... – Ori Pessach Apr 27 '10 at 15:44
  • Err .. I don't see what the CRTP has to do with virtual functions. The curiously recurring template pattern is about compile-time polymorphism , not runtime polymorphism. – Billy ONeal Apr 27 '10 at 15:45
  • @Billy Oneal - You're right. CRTP has nothing to do with virtual functions, but since virtual functions can't be used as C callbacks, and the question deals specifically with using C++ methods as C callbacks, it's perfectly appropriate here. – Ori Pessach Apr 27 '10 at 15:53
  • @Ori: Well, static member functions can't be portably used as C-callbacks either. – Georg Fritzsche Apr 27 '10 at 17:07
  • @gf - Yep, you're right. – Ori Pessach Apr 27 '10 at 17:28
  • @Billy, pure virtual functions are one way to require descendants to provide certain things for the base class to use. Since virtual functions can't work in this case, we can use another technique to force descendants to provide certain features; namely, CRTP. My answer demonstrates that. I hadn't noticed the deleted answer when I posted mine, but I think my answer does a better job of demonstrating it in the context of this question anyway (no type-casting required, and it builds a struct like the one the C code requires). – Rob Kennedy Apr 27 '10 at 17:55
  • Can some one explain me what: `ol'` means? – math Jan 17 '14 at 09:20
  • @math: It's an alternative way to write "old". – raven Jan 17 '14 at 10:08
  • "There's a good reason static virtual functions are not allowed." Disagree. "If you allow static virtuals, they could potentially be called from the [abstract] class with out instantiating it." So? If you implemented the static virtual for a class, then why shouldn't you be able to call it? "There would be nothing to prevent them from being called before they were defined!" <- If they weren't defined, you wouldn't be able to call them. – einpoklum Jul 13 '22 at 12:31

12 Answers12

24

You can make Base be a class template that takes its function pointers from its template argument:

extern "C" {
struct CStruct
{
  void (*funA)(int, char const*);
  int (*funB)(void);
};
}

template <typename T>
class Base
{
public:
  CStruct myStruct;
  void FillPointers() {
    myStruct.funA = &T::myFunA;
    myStruct.funB = &T::myFunB;
  }
  Base() {
    FillPointers();
  }
};

Then, define your derived classes to descend from an instantiation of Base using each derived class as the template argument:

class Derived1: public Base<Derived1>
{
public:
  static void myFunA(int, char const*) { }
  static int myFunB() { return 0; }
};

class Derived2: public Base<Derived2>
{
public:
  static void myFunA(int, char const*) { }
  static int myFunB() { return 1; }
};

int main() {
  Derived1 d1;
  d1.myStruct.funA(0, 0);
  d1.myStruct.funB();
  Derived2 d2;
  d2.myStruct.funA(0, 0);
  d2.myStruct.funB();
}

That technique is known as the curiously recurring template pattern. If you neglect to implement one of the functions in a derived class, or if you change the function signature, you'll get a compilation error, which is exactly what you'd expect to get if you neglected to implement one of the pure virtual functions from your original plan.

The consequence of this technique, however, is that Derived1 and Derived2 do not have a common base class. The two instantiations of Base<> are not related in any way, as far as the type system is concerned. If you need them to be related, then you can introduce another class to serve as the base for the template, and then put the common things there:

class RealBase
{
public:
  CStruct myStruct;
};

template <typename T>
class Base: public RealBase
{
  // ...
};

int main()
  RealBase* b;
  Derived1 d1;
  b = &d1;
  b->myStruct.funA(0, 0);
  b->myStruct.funB();
  Derived2 d2;
  b = &d2;
  b->myStruct.funA(0, 0);
  b->myStruct.funB();
}

Beware: Static member functions are not necessarily compatible with ordinary function pointers. In my experience, if the compiler accepts the assignment statements shown above, then you can at least be confident that they're compatible for that compiler. This code isn't portable, but if it works on all the platforms you need to support, then you might consider it "portable enough."

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • 1
    I guess i will for now be the one that nitpicks about the portability issues of using static member functions as C-callbacks: http://stackoverflow.com/questions/2068022/in-c-is-it-safe-portable-to-use-static-member-function-pointer-for-c-api-callb – Georg Fritzsche Apr 28 '10 at 01:12
  • When I first posted my answer, I hadn't considered that perhaps the assignment from static member function to function pointer only worked for me because *neither* was `extern C`. I merely figured that if my C++ compiler accepted the assignment statements, then they were at least compatible on my system. I've since gone back and made the struct `extern C`, and the code still works. Tested on Sun 5.8 and GNU 3.4.6 and 4.1.2. All three compile and run without warnings or errors. – Rob Kennedy Apr 28 '10 at 04:54
  • 1
    It might work on most compilers now, but i think it should at least be mentioned that it can break instead of implying that using static member functions is perfectly fine. – Georg Fritzsche Apr 28 '10 at 17:28
16

I think you just need to use a plain virtual function. A static virtual function does not make sense, because a virtual function is resolved at runtime. What's there to resolve when the compiler knows exactly what the static function is?

In any case, I would suggest leaving the existing function pointer solution in place if possible. Baring that, consider using a normal virtual function.

Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
  • 1
    What do you mean with "use a plain virtual function"? I cannot cast it to a function pointer, so... – raven Apr 27 '10 at 14:32
  • You can't call a virtual function from C code, because C doesn't know about virtual method tables. – Ori Pessach Apr 27 '10 at 15:17
  • @Jaime Pardos: Which function a virtual function actually calls is not known, unless the type to which that virtual function calls is known. If you want your callback function to be virtual, sorry, but there's no way to do that. Given though that forcing a cast to a function pointer is the reason you are using `static` in the first place, this is not a plug in solution. But given that your original question did not contain that information I think my interpretation is a reasonable response. – Billy ONeal Apr 27 '10 at 15:41
  • 2
    **"[...]Now, I have a plain ol' C SDK that uses function pointers heavily. I have to fill a structure with several function pointers. I was planning to use an abstract class with a bunch of static pure virtual methods, and redefine them in derived classes and fill the structure with them. It wasn't until then that I realized that static virtual are not allowed in C++."** I'd say it was pretty clear. – raven Apr 27 '10 at 15:47
  • @Jaime: I see nothing about passing virtual functions *into* that C sdk, nor do I see anything about casting those static virtual functions into function pointers. – Billy ONeal Apr 27 '10 at 15:54
  • "I have to fill a structure with several function pointers [...] static pure virtual methods [...] redefine them in derived classes and fill the structure with them" I'll accept your answer if you want the points so badly but, dude, lrn2read. – raven Apr 27 '10 at 19:04
  • @Jaime: I don't see the word cast, or any mention of passing into the C callback. You're saying you want derived classes to use different function pointers. I don't expect you to accept this answer, but I want to help you ask better questions. Say what you want to do ("pass virtual functions into a C API which only accepts function pointers") instead of a possible way you think you might be able to do this ("I want a static virtual function"). The fact that the function is static tells me absolutely nothing about what you want to *do* with it. – Billy ONeal Apr 27 '10 at 22:33
  • For what it's worth, I read the above assuming you had a C API which used function pointers which you wanted to refactor into C++ virtual functions. – Billy ONeal Apr 27 '10 at 22:34
  • @Billy: Ok, now I see what's going on there. When I wrote "fill the structure with them" I really meant "put them in the function pointers of the structure", not "fill the structure FROM them". The API is a third party library so I can't touch it. I could argue why it was implicit if you carefully read all the question but it's pretty pointless now. I thank you for your comments, anyway, and will try to keep them in mind in order to ask better questions in the future. To show you I am not resentful or anything, I will accept your answer. – raven Apr 27 '10 at 23:36
  • Billy, I'm not sure the text of your answer really answers the question. Since it's the accepted one, could you please edit it so that it incorporates what came out in the comments. (Comments aren't shown by default for old questions, and I wouldn't want the answer to be buried in hidden comments.) – Rob Kennedy Apr 28 '10 at 17:59
  • @Rob Kennedy: I would do that if I had any idea why he accepted this answer. (Personally I don't think I deserve the checkmark here) – Billy ONeal Apr 28 '10 at 18:10
12

I still can see a use for static virtual methods, here an example:

class File
{
    static virtual std::string extension()  {return "";}
}

class ExecutableFile : public File
{
    // static because every executable has same extension
    static virtual std::string extension()  {return ".exe";}
}


std::string extension = "";

// needing static
extension = ExecutableFile::extension();

// not needing static nor virtual
ExecutableFile exeFile;
extension = exeFile.extension();

// needing virtual
File* pFile = &exeFile;
extension = pFile->extension();
Eno
  • 121
  • 1
  • 2
6

A common pattern when passing a function pointer (a callback) to a C SDK uses the fact that many such functions allow a void * parameter that is "user data". You can define your callbacks to be simple global functions, or static class member functions. Then each callback can cast the "user data" parameter to a base class pointer so you can call a member function that does the work of the callback.

Permaquid
  • 1,950
  • 1
  • 14
  • 15
  • Sadly, this is not the case, this functions signature doesn't haev a userData param. – raven Apr 27 '10 at 14:42
  • @Jaime: If you'd have added such facts to your question we would all have wasted less time. – Georg Fritzsche Apr 27 '10 at 17:11
  • I guess i will for now be the one that nitpicks about the portability issues of using static member functions as C-callbacks: http://stackoverflow.com/questions/2068022/in-c-is-it-safe-portable-to-use-static-member-function-pointer-for-c-api-callb – Georg Fritzsche Apr 28 '10 at 01:14
  • Thank you again, gf. No problem, I'm stuck with windows in this. But it's something worth keeping in mind in the future. – raven Apr 28 '10 at 13:50
6

You could just pass the functions directly into the base class constructor:

class Base
{
    Base()(int (*myFunA)(...), int (*myFunB)(...)) 
    { myStruct.funA = funA; myStruct.funB = myFunB; ...}
private:
    CStruct myStruct;
};

class Derived1 : public Base
{
    Derived1() : Base (myFunA, myFunB) {}
    static myFunA(...) {...};
    static myFunB(...) {...};
};

class Derived2 : public Base
{
    Derived2() : Base (myFunA, myFunB) {}
    static myFunA(...) {...};
    static myFunB(...) {...};
};

int main()
{
    Derived1 d1;
    Derived2 d2;
    // Now I have two objects with different functionality
}
Eclipse
  • 44,851
  • 20
  • 112
  • 171
5

If the derived type of an object can be determined at compile time, you can use the "Curiously Recurring Template Pattern" to achieve static polymorphism. With this approach you are not limited to just overriding virtual non-static member functions. Static and non-function members are fair game. You can even override types (but the base object size can't be a function of the those types).

#include <iostream>
#include <stdint.h>

struct VirtualBase {
    static const char* staticConst;
    static char* staticVar;
    static char* staticFun() { return "original static function"; }
    const char* objectConst;
    char* objectVar;
    virtual char* objectFun() { return "original object function"; }
    typedef int8_t Number;
    VirtualBase():
        objectConst("original object const"),
        objectVar("original object var")
    {}
    void virtual_dump(std::ostream& out=std::cout) {
        out << this->staticConst << std::endl;
        out << this->staticVar << std::endl;
        out << this->staticFun() << std::endl;
        out << this->objectConst << std::endl;
        out << this->objectVar << std::endl;
        out << this->objectFun() << std::endl;
        out << "sizeof(Number): " << sizeof(Number) << std::endl;
    }
};
const char* VirtualBase::staticConst = "original static const";
char* VirtualBase::staticVar = "original static var";

template <typename Derived>
struct RecurringBase: public VirtualBase {
    void recurring_dump(std::ostream& out=std::cout) {
        out << Derived::staticConst << std::endl;
        out << Derived::staticVar << std::endl;
        out << Derived::staticFun() << std::endl;
        out << static_cast<Derived*>(this)->staticConst << std::endl;
        out << static_cast<Derived*>(this)->staticVar << std::endl;
        out << static_cast<Derived*>(this)->staticFun() << std::endl;
        out << static_cast<Derived*>(this)->objectConst << std::endl;
        out << static_cast<Derived*>(this)->objectVar << std::endl;
        out << static_cast<Derived*>(this)->objectFun() << std::endl;
        out << "sizeof(Number): " << sizeof(typename Derived::Number) << std::endl;
    }
};

struct Defaults : public RecurringBase<Defaults> {
};

struct Overridden : public RecurringBase<Overridden> {
    static const char* staticConst;
    static char* staticVar;
    static char* staticFun() { return "overridden static function"; }
    const char* objectConst;
    char* objectVar;
    char* objectFun() { return "overridden object function"; }
    typedef int64_t Number;
    Overridden():
        objectConst("overridden object const"),
        objectVar("overridden object var")
    {}
};
const char* Overridden::staticConst = "overridden static const";
char* Overridden::staticVar = "overridden static var";

int main()
{
    Defaults defaults;
    Overridden overridden;
    defaults.virtual_dump(std::cout << "defaults.virtual_dump:\n");
    overridden.virtual_dump(std::cout << "overridden.virtual_dump:\n");
    defaults.recurring_dump(std::cout << "defaults.recurring_dump:\n");
    overridden.recurring_dump(std::cout << "overridden.recurring_dump:\n");
}

Here is the output:

defaults.virtual_dump:
original static const
original static var
original static function
original object const
original object var
original object function
sizeof(Number): 1
overridden.virtual_dump:
original static const
original static var
original static function
original object const
original object var
overridden object function
sizeof(Number): 1
defaults.recurring_dump:
original static const
original static var
original static function
original static const
original static var
original static function
original object const
original object var
original object function
sizeof(Number): 1
overridden.recurring_dump:
overridden static const
overridden static var
overridden static function
overridden static const
overridden static var
overridden static function
overridden object const
overridden object var
overridden object function
sizeof(Number): 8

If the derived type cannot be determined until run-time, just use a virtual non-static member function to gather static or non-function info about the class or object.

Eric Mahurin
  • 51
  • 1
  • 2
4

These things would certainly be useful- namely, to force all objects in a class hierarchy to expose a factory method instead of an ordinary constructor. Factories are very useful for ensuring you never build invalid objects, a design guarantee that you cannot enforce nearly as well with ordinary constructors.

To build 'virtual statics' requires building your own "static v-table" by hand into all the objects that need it. Ordinary virtual member functions work because the compiler builds a secret table of function pointers called the VTABLE into all instances of your class. When you build a "T" object, the function pointers in this table are assigned to the addresses of 1st ancestor providing that API. Overriding a function then simply becomes replacing the original pointer in the object you get from 'new' with the new one provided in the derived class. Of course, the compiler and runtime handle this all for us.

But, back in the really old days before modern c++ (so I'm told), you had to set this magic up yourself. And that's still the case for virtual statics. The good news is this- the vtable you build by hand for them is actually simpler than the 'ordinary' one, its entries are no more expensive in any way-including space & performance- than those for member functions. Just define the base class with an EXPLICIT set of function pointers (the static vtable) for the APIs you want supported:

template<typename T>
class VirtualStaticVtable {
private:
   typedef T (*StaticFactory)(KnownInputParameters params);

   StaticFactory factoryAPI;  // The 1 and only entry in my static v-table

protected:
   VirtualStaticVtable(StaticFactory factoryApi) : factoryAPI(factoryApi) {}
   virtual ~VirtualStaticVtable() {}
};

Now, every object that should support a static factory method can be derived from this class. They quietly pass in their own factory to their constructor, and it only adds 1 pointer to the resulting objects' sizes (just like an ordinary VTable entry).

Strousup and co. could still add this idiomatic pattern to the core language if they wanted to. It wouldn't even be that hard. Every object in such a "C+++" would simply have 2 vtables instead of 1- 1 for member functions taking 'this' as an argument and 1 for ordinary function pointers. Until that day, however, we're stuck with manual vtables just like the old C-programmers were in the days before c++.

Zack Yezek
  • 1,408
  • 20
  • 7
3

Assuming that the C SDK allows you to pass it a void * to your data (and you should pass it your this pointer for the derived class:)

class Base {

  public:

    void Initialize() { /* Pass /this/ and a pointer to myFuncAGate to your C SDK */ }

    virtual myFuncA()=0;

    // This is the method you pass to the C SDK:
    static myFuncAGate(void *user_data) {
        ((Base*)user_data)->myFuncA();
    }
};


class Derived1: public Base {
  public:
    virtual myFuncA() { ... } // This gets called by myFuncAGate()
};

If the C SDK doesn't allow you to pass a pointer to your data which is then passed back to you through the callbacks, then you'll have a really hard time doing this. Since you indicated in one of your comments that this is indeed the case, you're pretty much out of luck. I would suggest using simple functions as callbacks, or overloading the constructor and defining multiple static methods. You'll still have a hard time determining what's the proper object your methods are supposed to work with when your callbacks are invoked by the C code.

If you post more details about the SDK it might be possible to give you more relevant suggestions, but in the general case, even with static methods, you need some way of obtaining a this pointer to work with.

Ori Pessach
  • 6,777
  • 6
  • 36
  • 51
2

Virtual functions are essentially function pointers under-the-hood. They just point to different functions for different classes. To simulate virtual-function behavior, have a function pointer stored somewhere, then to 'override' it just reassign it to some different function.

Alternatively, you might want to test this, but I think interfaces have pretty good binary compatibility. You might get away with exposing a C++ interface composed entirely of pure virtual functions, so long as all the parameters and return types have a consistent binary format (eg. C types). It's not a standard, but it might be portable enough.

AshleysBrain
  • 22,335
  • 15
  • 88
  • 124
  • 1
    Err... that's true, but how does that answer the OP's question? :) – Billy ONeal Apr 27 '10 at 14:23
  • The OP understands quite well what a virtual function is, and understands that it isn't possible to do what he wanted with them. That's why he asked for an **alternative**. – raven Apr 27 '10 at 15:24
  • @Jaime - OK, sorry for being snide. I had the vague, half baked notion that anyone could reach a working solution to your problem just by understanding the underlying principals and thinking about it for a few minutes. I since took a stab at it myself and find that I was wrong - there are subtleties here that aren't obvious. I was rude, and I apologize. I'll remove the comment since it is unhelpful. – Ori Pessach Apr 27 '10 at 20:26
  • No problem, Ori. Can't see the advantages of deleting your comment, however, but still... – raven Apr 27 '10 at 23:14
2

The obvious way is like this, with FillPointers implemented in each derived class.

class Base
{
private:
    CStruct myStruct;
};

class Derived1 : public Base
{
 private:
    static FillPointers() { myStruct.funA = myFunA; myStruct.funB = myFunB; ...}
    Derived1() {  FillPointers();  }
    static myFunA(...) {...};
    static myFunB(...) {...};
};

However you can probably avoid that using some template magic...

Roddy
  • 66,617
  • 42
  • 165
  • 277
  • Thank you, I think this would be one of the best answers, if it hadn't missed the "template magic" details. – raven Apr 27 '10 at 23:41
2

If the C SDK wants you to perform operations without providing a userdata, then object-orientation is likely unnecessary and you should just write some functions. Else, time to find a new SDK.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • I'm stuck with the SDK. About the other part of your answer, interesting answer. I think it's wrong, however, in some sense of "wrong"; object-orientation is ALWAYS unnecesary, but I felt it would be interesting to encapsulate everything in a class, and, having different sets of functions for different functionality, build a class hierarchy to make everything as easy to use and maintainable as my skill allows. I will think about this. – raven Apr 27 '10 at 23:46
2
class Base
{
    template<class T>
    FillPointers(T* dummy) { myStruct.funA = T::myFunA; myStruct.funB = T::myFunB; ...}
private:
    CStruct myStruct;
};

class Derived1 : public Base
{
    Derived1() {  FillPointers(this);  }
    static myFunA(...) {...};
    static myFunB(...) {...};
};

class Derived2 : public Base
{
    Derived2() {  FillPointers(this);  }
    static myFunA(...) {...};
    static myFunB(...) {...};
};

int main()
{
    Derived1 d1;
    Derived2 d2;
    // Now I have two objects with different functionality
}

see also C++ static virtual members?

Community
  • 1
  • 1
Alsk
  • 1,100
  • 6
  • 11