-
C++: C with Crashes...
Today I am going to tell you about a potentially unforseen feature of the C++ language (or rather the compiler's interpretation of the language) that makes using callbacks not just difficult (you already knew that!), but deadly. Let me explain:
Assume you have a base class called cBase, with a derived class cDerived. The base class defines a linked list of cBase:: callbacks, and also a plethora of methods for manipulating the list.
Now cDerived defines a new function with a signature compatible with the list, and with a little static_cast<> prodding, pushes the function into it. At some later time, the list is traversed, and the functions are invoked. Crash! What the hell happened, you say?
The culprit was in derefrencing (both implicitly and explicitly) the "this" pointer(!) on cDerived's members within the functions. Even though the functions were declared within the class using them, because of the cast, they are rendered virtually useless! You simply cannot make it work! Wow, that sucks, you say. Oh, but that's not all!!
So being the clever shmuck that you are, you decide to give cBase a new member, a void * pointer named "work_around", and cDerived a pointer to a cDerived named "This". You pass "this" into the cBase function that swallows callbacks, and point "work_around" to it. Later, in cDerived's constructor, you cast "work_around" into a cDerived and assign it to "This". The functions themselves internally use "This->", not "this->"... sounds bulletproof, right?
Well, unless there is some flaw in my logic here(or even my compiler), no. The results were identical. The moral of the story is that C++ is not perfect, and can be quite a pain at times. Having said that, I cannot see myself parting with it any time soon, but -to be sure - whatever ugly hack I must come up with to work around this obnoxious problem will always serve as solemn reminder to me that SOMEDAY...I MUST WRITE MY OWN COMPILER!!!
You have been forewarned!
-
What are you trying to do seba?
could you illustrate it with a code sample?
-
How about deriving from cBase (with a member function called doIt(), or something more applicable) for as many different functions you want to have called back. Instead of keeping a list of pointer to cBase functions in cBase, keep a list of cBase*. Each time you want to call something from cBase, simply call the doIt member of whatever is in the list. You get the same not determined til runtime what function will be called, except no crashes.
-
This specifically relates to creating a mechanism that makes the standard WindowProcedure an invisible, unchanging entity. Instead, derived classes simply "announce" the message they're interested in and tie it to a Windows message. Message mapping.
Here's an example I posted to another thread. The program is "complete", and runs as is:
Code:
class button : public Button {
public:
button(int w, int h) {
SetWidthHeight(w, h);
Register(&button::Hello, WM_LBUTTONDOWN); //..."the map"..
}
void Hello() {
Alert("Stop clicking me!!!");
}
};
button b(100, 25);
int WINAPI WinMain(/**/){
win.Create(); //..use defaults, for clarity.
b.Create(&win);
return win.RunMessageLoop();
}
-
Well, the whole idea is not having to predetermine anything in your implementation. Classes simply define their own functions, and register them. Before, I did similar to what you're saying, except I defined virtual functions, OnLeftButtonDown(), and so forth. But whenever I thought of a new handler, I had to add code to my library. Thus the need for change...
-
In that case, I can see my solution really wouldn't work. You could instead have a virtual onLButtonDown member of the base class, which is called by whatever is handling the messages on your subclass of button.
Code:
class button : public Button {
public:
button(int w, int h) {
SetWidthHeight(w, h);
}
void onLButtonDown() {
Alert("Stop clicking me!!!");
}
};
-
Heh... posted that right before I read your response.
What do you mean that you need to change your library everytime you add a new handler? Shouldn't the handler itself just be relaying messages to the other objects?
-
Reads fine if you start from the bottom of the thread :D
-
-
sorry crappy php link not working. go to that site and look for this tutorial....
Creating a Win32 Window Wrapper Class
by Oluseyi Sonaiya
-
This works for me.
Code:
#include <iostream>
class Base
{
public:
//Runs the function stored in the pointer
void ExecuteFunction();
protected:
typedef void (Base::*base_func_ptr)(int);
template<class T>
void Connect(void (T::*func)(int))
{
func_ptr = static_cast<base_func_ptr>(func);
}
base_func_ptr func_ptr;
};
void Base::ExecuteFunction()
{
(this->*func_ptr)(15);
}
class Derived:
public Base
{
public:
//Member function to be added to Base
void Test(int i)
{
//Output a simple multiplication, using a member
//variable and the argument
std::cout << member*i;
}
Derived():
member(3)
{
Connect(Test);
}
int member;
};
int main()
{
Derived d;
d.ExecuteFunction();
std::cin.ignore(1000,'\n');
}
(edit) Now using template (/edit)
(edit2) Now works in VC++.NET (/edit2)
-
Unfortunately, it still crashes =(
-
What compiler are you using?
My code works in CodeWarrior.
(Edit: also works in VC++.NET )