views:

217

answers:

4

I have a GUI architecture wherein elements fire events like so:

guiManager->fireEvent(BUTTON_CLICKED, this);

Every single event fired passes 'this' as the caller of the event. There is never a time I dont want to pass 'this', and further, no pointer except for 'this' should ever be passed.

This brings me to a problem: How can I assert that fireEvent is never given a pointer other than 'this', and how can I simplify (and homogenize) calls to fireEvent to just:

guiManager->fireEvent(BUTTON_CLICKED);

At this point, I'm reminded of a fairly common compiler error when you write something like this:

class A {
public:
    void foo() {}
};

class B {
    void oops() { const A* a = new A; a->foo(); }
};

int main() {
    return 0;
}

Compiling this will give you

In member function ‘void B::oops()’: error: passing ‘const A’ as ‘this’ argument of ‘void A::foo()’ discards qualifiers

because member functions pass 'this' as a hidden parameter.

"Aha!" I say. This (no pun intended) is exactly what I want. If I could somehow access the hidden 'this' pointer, it would solve both issues I mentioned earlier. The problem is, as far as I know you can't (can you?) and if you could, there would be outcries of "but it would break encapsulation!" Except I'm already passing 'this' every time, so what more could it break.

So, is there a way to access the hidden 'this', and if not are there any idioms or alternative approaches that are more elegant than passing 'this' every time?

+6  A: 

You could define

void Element::fireEvent(EVENT e) {
   guiManager->fireEvent(e, this);
}

to save yourself a bit of writing each time. You're going to have to call it with this at some point, since the guiManager needs to know which Element called fireEvent.

Jesse Beder
A: 

I'm not sure I understand the latter half of your question (and one thing at a time is a good rule here), but in the case of:

guiManager->fireEvent(BUTTON_CLICKED, this);

you could give the class this code is called from a constructor that takes a guiManager as a parameter - call it mGM. And then provide a member function that looks like this:

void FireEvent( EventType e ) {
   mGM->fireEvent( e, this );
}

whicch you call as:

FireEvent( BUTTON_CLICKED );
anon
+1  A: 

It depends of guiManager's scope.

You could rewrite it:

class MyClass
{
public:

private:
  void FireEvent(GuiManager* guiManager, EventType e)
  {
    assert(guiManager);
    guiManager->FireEvent(e, this);
  }
};

Is there a reason to pass this (of type MyClass*) rather than *this (of type MyClass&) ? If you pass a pointer it means you expect the object to be possibly NULL... and this is never NULL (baring dangerous exploits of undefined behavior)

Matthieu M.
A: 

Another option is to create a #define macro so the compiler will add the "this" parameter for you. It would look something like this:

#define FIREEVENT(gm,e) gm->fireEvent(e, this)
FIREEVENT(guiManager, BUTTON_CLICKED); //compiles as: guiManager->fireEvent(BUTTON_CLICKED);

Although, I don't recommend this and I tend to cringe anytime I see C++ macros because they usually make code harder to understand and can cause really confusing compiler errors.

J Higs