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 us
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?
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...
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.
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.
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.
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.