My problem is that when I call a virtual function on an object passed to my callback function, the wrong function gets called, and I get a run-time error.
Consider the following code fragment in a header file. The code may not compile as it is only a fragment.
class CEventBase1{
protected:
virtual void Show(int code){}
private:
static void _Base1Callback(void*ptr){
CEventBase1* pThis = static_cast<CEventBase1*>(ptr);
pThis->Show(EVENT_CODE);
}
};
class CEventBase2{
protected:
virtual void Move(int code){}
private:
static void _Base2Callback(void*ptr){
CEventBase2* pThis = static_cast<CEventBase2*>(ptr);
pThis-> Move(EVENT_MOVE);
}
};
class CAllEvents: public CEventBase1, public CEventBase2{
};
template<typename EVENTS>
class CWindow : public EVENTS{
};
class CMyEvents: public CAllEvents{
public:
virtual void Move(int code){
// Some processing
}
};
CWindow<CMyEvents> myWin;
This code will interact with some library in which the window instance is registered to handle events. Something similar to:
int main () {
SomeLibraryRegisterCallbackData(&myWin);
SomeLibraryRegisterEvent1Callback(CEventBase1::_Base1Callback);
SomeLibraryRegisterEvent2Callback(CEventBase2::_Base2Callback);
return SomeLibraryDispatch();
}
The idea is that during the dispatch, the pointer to myWin gets passed to a registered callback whenever the event it is registered against occurs.
Problem: When the program tries to call the CMyEvents::Move() from the static function _Base2Callback(), the CEventBase1::Show() function gets called and the program crashes in the caller function as soon as Show() returns with the error:
ESP pointer is of incorrect type. this may happen when an incorrect method is called
Compiler: Visual C++ 2012.
Since you are passing in a pointer to a CWindow<CMyEvents> instance to CEventBase2::_Base2Callback, then the static cast of the void * argument to CEventBase2 * is in error. Although there is an is-a relationship between the two, it is through multiple inheritance. In practical terms, this means that the object layout is such that for an instance of CMyEvents, its address is not the same as the address of the CEventBase2 instance from which it is derived.
The straightforward way to avoid this problem is to avoid using void * altogether. However, since you are using a library, then you must make your code compatible with the framework. In your case, you want each base class to define its own callback function. This means that the base class needs to be aware of the derived type, because it is the pointer to the derived type that is being passed into the callback function.
This can be accomplished using CRTP. Make each base class a template class that is parameterized by its derived class. Then, the callback function can cast to the derived type:
template <typename DERIVED>
class CEventBase1{
protected:
virtual void Show(int code){}
protected:
static void _Base1Callback(void*ptr){
DERIVED* pThis = static_cast<DERIVED*>(ptr);
pThis->Show(EVENT_CODE);
}
};
template <typename DERIVED>
class CEventBase2{
protected:
virtual void Move(int code){}
private:
static void _Base2Callback(void*ptr){
DERIVED* pThis = static_cast<DERIVED*>(ptr);
pThis-> Move(EVENT_MOVE);
}
};
You would also make CAllEvents a template class as well, so it can properly pass the right derived type to the base classes:
template <typename DERIVED>
class CAllEvents: public CEventBase1<DERIVED>, public CEventBase2<DERIVED>{
};
And now, the user of the of that class uses it like this:
class CMyEvents: public CAllEvents<CMyEvents>{
public:
void Move(int code){
// Some processing
}
};
Because of the way CWindow<> is defined, the address of an instance of it would be the same as the address of the CMyEvents instance from which it is derived. The callback functions in the base classes will cast the pointer to a CMyEvents*.
Related
I'm writing a module system for my program, where individual modules are initialised and shutdown by a system.
how this works is I call an Init() function that will initialise a static pointer of the class.
this works and is fine, however: I would like to abstract this into a class so the api is easier to maintain, but I don't know how to change the pointer type of the derived class automatically
for example, if I have the base class IModule:
class IModule {
public:
protected:
result Init();
result Shutdown();
private:
static IModule* s_instance;
};
is there a way I can write this class so that the derived class can be written as
class Derived : public IModule {
protected:
result Init();
result Shutdown();
}
and have Derived::s_instance evaluate to a Derived*
No, you can't have a variable whose type depends on the type of this. However, you can have a variable whose type depends on a template parameter.
template <typename T>
class IModule {
private:
static T* s_instance;
};
class Derived : public IModule<Derived> {
// The s_instance in this class is of type Derived*.
}
This is called the curiously recurring template pattern and it's used to do all sorts of tricks in C++. It may not work for your use case (for instance, you can no longer have a list of IModule which all have different derived types), but depending on what exactly you're doing this may be the way to go.
You can do this as long as the return types are covariant, i.e., Derived::Init() returns something derived from Derived::IModule()'s return type. Which is I think the case here. A simplified version:
#include <iostream>
struct IModule {
virtual IModule* Init() = 0;
private:
static IModule* s_instance;
};
class Derived : public IModule {
Derived* Init() override { std::cout << "1" << std::endl; return this; }
};
int main() {
IModule* ptr = new Derived();
ptr->Init(); // compile-time type: IModule, runtime: Derived
}
This is a question about designing classes in C++.
My base class have virtual final method with parameters, the name of it is basically "update". In a child class, I wanted to use a higher level way to update the object, so I made a method called "update" too (for convenience), but this one have no parameter. And Clang warns me the method is hiding a base class method. In my point of view, I'm not totally agree with this, because the signature is different, it should just complete the overloading.
Is there a good reason to not do that ?
The warning is telling you that the function in the derived class makes it more difficult to call the original base class function on an object of the derived type:
class Base {
public:
virtual void update(int param) final;
};
class Derived : public Base {
public:
void update();
};
void f(Derived& obj) {
obj.update(2); // Error!
// Name lookup for update finds only Derived::update,
// which takes no arguments
}
To "unhide" the base class function, so that the derived class acts as though it has both overloads, use a using directive:
class Derived : public Base {
public:
void update();
using Base::update;
};
It is very easy that we can make sure derived class must implement interface defined in base class.
That is pure virtual function.
For example:
class BaseClass
{
...
virtual void print()=0;
...
}
class DerivedClass :public BaseClass
{
// function must be implement, otherwise compiler will complain ...
void print()
{
}
};
Can we defined a static interface in base class and make sure the interface must be implement in derivate class?
I want something like this
class BaseClass
{
...
static void print(); // base class only define static interface
...
}
class DerivedClass :public BaseClass
{
// derived class must implement interface, otherwise compiler will complain ...
static void print()
{
}
};
I have no idea about this.
Thanks for your time.
It is not possible to make a virtual static function. For the simple reason that when calling a static function, you always know the class that defines that function in compile time. Unlike virtual functions, where you don't know the type of the object whose method you're calling.
For example:
class A
{
public:
virtual void f() {printf("A");}
};
class B : public A
{
virtual void f() override {printf("B");}
};
void g(A& a)
{
a.f();
}
int main()
{
B b;
g(b);
return 0;
}
In the above example, inside the function g, the correct function is invoked (B::f). Even though while compiling the function it is not known what the type of its argument is (it could be A or any class derived from A).
Without making f() virtual, you would have overloaded the method f, rather than overridden it. Which means that in the following example, the output would be "A", even though you might expect it to be "B":
class A
{
public:
void f() {printf("A");}
};
class B : public A
{
void f() {printf("B");}
};
void g(A& a)
{
a.f();
}
int main()
{
B b;
g(b);
return 0;
}
This may cause serious bugs, and it is suggested to never overload base class methods, and to always use the override keyword when overriding a virtual method to escape those bugs.
When making a static function, you can simply overload it, it would not create a compilation error. However, you probably never should overload it, because it may hide a bug that is very difficult to track (you are certain that B::f() is being called while actually A::f() is being called).
Furthermore, it is not possible to 'force' the derived class to implement a static interface, because there is no such thing as a static interface. Because you have no virtual static functions, you may not pass a reference or pointer to the interface that would implement this function.
What is the advantage of defining static methods with exact same signature as the interface method in the class which implements it .
class IInterface
{
public:
virtual void fn()=0;
}
class Impl :IInterface
{
public:
~Impl();
static void fn();
}
Impl::~Impl{
}
Impl::fn(){
//do something
}
There is no advantage of having such static method. static methods don't override virtual methods (which are always non-static).
In fact it has disadvantage, that you cannot implement the actual method to override the base method. Because one cannot have same method signature in a single class (one static and another non-static).
class Impl :IInterface
{
public :
~Impl();
staic void fn();
void fn() {} // error: invalid (can't have same signature)
};
There is no advantage.
Your derived class Impl still is as an Abstract class since it does'nt & can't override the pure virtual function. You cannot create any objects of it.
A static function cannot override a virtual function from Base class because dynamic polymorphism uses the this to evaluate the function call at run time, while static functions do not pass the this pointer, because they are not specific to any object.
I have a base class and a derived one and I want to change base functions while keeping them static as they should be passed to other functions as static.
How can I do that?
The ATL framework gets around the limitation of no virtual statics by making the base class be a template, and then having derived classes pass their class type as a template parameter. The base class can then call derived class statics when needed, eg:
template< class DerivedType >
class Base
{
public:
static void DoSomething() { DerivedType::DoSomethingElse(); }
};
class Derived1 : public Base<Derived1>
{
public:
static void DoSomethingElse() { ... }
};
class Derived2 : public Base<Derived2>
{
public:
static void DoSomethingElse() { ... }
};
This is known as Curiously recurring template pattern, which can be used to implement static polymorphism.
Do you mean you need a pointer to a static function (e.g. to pass as an argument to another function that requires a pointer to a static function), but you need to access that function pointer virtually? In that case, use a virtual function to get the function pointer:
typedef void (*function)();
void do_stuff_with_function(function);
struct Base {
virtual ~Base() {}
virtual function get_function() = 0;
};
struct Derived : Base {
function get_function() {return my_function;}
static void my_function();
};
Derived d;
do_stuff_with_function(d.get_function());
static function can not be virtual since they do not have an instance through which they are accessed. I do believe you can overwrite them though.
You can't have static virtual functions in C++.
Virtual functions typically rely on this pointer to determine the type of function to be called at run time.
A static member function does not pass a this so static virtual functions are not allowed in C++.
If i am correct in understanding ur question, then u can follow the following approach otherwise ignore..
have static function pointer in the base class.
in base class have a static function ( in which u call the function by using that static function pointer)..
in derived classes set that static function poiter to the function defination u wish to execute.. ( in base class u can set the function pointer to some default function).
You cannot have static virtual functions, because it doesn't make sense to have them.