gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

C/C++ > function pointers

#10146 - johnny_north - Thu Aug 28, 2003 3:11 am

If I have this member function:

void Console::VBL(){
//blah
}

and this:

typedef void (*IntrFuncp)(void);

void (*IntrTable[14])();

What's the right way to set an entry? This doesn't work:

IntrTable[0] = console.VBL;

#10149 - torne - Thu Aug 28, 2003 9:35 am

As far as I (and the C++ people I just asked around the lab) know, you can't take a normal pointer to an instance method. The problem you have is that there are two pieces of information; the method to call, and the object to call it on. A function pointer is just that, a pointer, and you can't include both pieces of information in it. I take it from context that you are trying to stuff instance methods into an interrupt vector; you will either need to use static methods (IntrTable[0] = &Console::VBL should work if VBL is static), or write a normal method which looks in some global variable for an instance of Console and calls the method on it, then put a pointer to that normal method in the vector. You may want to consider redesigning your code; Console sounds to me like an object that only has one instance (since the GBA has only one screen), so perhaps its methods could all be static?

#10155 - beelzebub - Thu Aug 28, 2003 12:03 pm

You can do function pointers to c++ classes, see below....

Code:

class cCLASS
{
public:
   void SetMode (int Mode);

   void Process1 (float Time);
   void Process2 (float Time);

    inline void Process (float TimeElapsed)
   {
        if (this->mp_process)
            (this->*mp_process) (TimeElapsed);
   }

  void (cCLASS::*mp_process) (float TimeElapsed);
}

void cCLASS:SetMode (int Mode)
{
    if (Mode == 1)
        mp_process = Process1;
   else
        mp_process = Process2;
}



Hopefully that should get you going.

The b*ll*cks to do with this in the Process() function IS required by the compilers :(

#10156 - torne - Thu Aug 28, 2003 12:31 pm

Those are pointer-to-member pointers, not function pointers. They can only be invoked on an instance of the class: in your example, you have to have an instance of cClass to call the Process method. johnny_north is trying to make an interrupt vector; you won't have a class instance handy in your ISR unless you have a vector of those as well. =)

Looking at johnny's original code, it looks like he just wants to have interrupts handled by objects. This is fair enough =). Since the method signatures are likely to always be the same (i.e. only one VBL function..etc) then there's no need to use pointer-to-members. A tiny wrapper function which looks up which instance of an object to call will do:
Code:
void VBL()
{
  g_console.VBL();
}

would be sufficient (where g_console is some global variable that points to the instance of Console in use). This is now a normal function and can be put into an interrupt vector the normal way =)

#10157 - johnny_north - Thu Aug 28, 2003 1:26 pm

Yes, I've had to handle my interupts using a "global function layer." I was concerned that there might be a better way. Thanks for the help.

I guess that answers my next question: If you are using C++ and an interupt vector (like I listed above/Jeff F's crt0), then it is necessary to have at the minimum one global instance of a class - to catch the necessary interupts and disburse them. Anything wrong with this approach?

#10160 - torne - Thu Aug 28, 2003 2:18 pm

Not if you want to do it that way. Personally, for classes like your Console, which I assume is only ever going to have one instance, I wouldn't use a class at all, or I would use an entirely static class. (as I noted already, you should be able to take a pointer to a static method in the usual way). You don't have to put everything in a class; C++ is not Java. (note: I like Java, I'm not mocking it) This is just my personal style of programming, and I don't encourage anyone to imitate my habits as many of them are probably bad. =)

Any way that works is fine, remember! A technique that has readable code is an advantage, but to be honest, whether a piece of code is object-oriented or not rarely makes any different to how readable it is (bad or inexperienced programmers manage to write code that's hard to read with or without OO; good, experienced programmers manage to write code that's easy to read with both too). =)

#10166 - sajiimori - Thu Aug 28, 2003 8:05 pm

"A technique that has readable code is an advantage, but to be honest, whether a piece of code is object-oriented or not rarely makes any different to how readable it is..."

Amen, brother! ;-) I went through half a project trying to make everything proper OO before coming to the conclusion that switching on types, for instance, is often much simpler, more readable, and even (*gasp*) more maintainable than a class hierarchy with virtual methods.

I still use inheritance and polymorphism occasionally, but I've come to consider simplicity one of the highest priorities (just below "correctness"), and I can almost always come up with a simpler solution that is not OO.

#10169 - torne - Thu Aug 28, 2003 8:08 pm

Exactly. OO is a tool, to be used where appropriate. I do a lot of Java coding when not working on the GBA (I do only ASM on the gba, because C is too easy *grin*), and I manage to write procedural code just fine in it, even with mandatory classes.

If code can be understood, is correct, and is not fundamentally inefficient, it is okay. =)

#10188 - bomberman - Fri Aug 29, 2003 8:16 am

just a small note...

I agree entirely with torne's new post.
What I do, when I want to avoid a singleton class or a class with exposes only static functions (whihch is ugly I think), I just declare all my functions in a namespace. This way, the functions are still related (they belong to the same namespace, and this is nice) but we don't see any dummy class which are not useful at this time.

#10198 - torne - Fri Aug 29, 2003 11:54 am

I don't see why it's ugly; the resulting object files are effectively identical. =)
A class is also a namespace, you know.

#10199 - bomberman - Fri Aug 29, 2003 12:39 pm

The object code called is the same, but it's not actually true that a class is a namespace :O)
For a class, it will create some code for a default constructor and a default destructor at least... It's not a big deal, true, however with a limited platform like this one, it can have its importance ! So technically they are not EXACTLY the same.
On a more conceptual note, a class represents an entity. Its ultimate goal is to be instanciated and derived. When you have a set of functions to deal with something related to a given domain, the concept of namespace is the good one to use... that is my opinion.
But I agree there is not lots of differences... It's just that it is cleaner to do so !

#10204 - torne - Fri Aug 29, 2003 1:54 pm

A class is a namespace. Honest. An area declared with the 'namespace' keyword is also a namespace. The former is not implemented in terms of the latter. =) Though yes, it will spawn a noop constructor and destructor.

A class does not represent an entity on a conceptual level; an object does. A class is two things. The static members of a class constitute a namespace with no interesting properties at all compared to a 'normal' namespace declared with the keyword. The nonstatic members of the class constitute a prototype for object construction. (the automatically generated constructor/destructor are a part of the latter).

This could pretty much be argued until the end of time. I rarely have cause to program in C or C++, so I don't really care all that much. As I said, most of my code is Java, which, not having a namespace construct other than classes, doesn't give you the choice. =)