Using a function pointer array in a class

Discussion in 'Programmer's Corner' started by mentaaal, Sep 4, 2008.

  1. mentaaal

    Thread Starter Senior Member

    Oct 17, 2005
    451
    0
    Hi!

    I am trying to use a function pointer array in a class but its not working. I tried doing exactly the same thing without a class here and it works fine:

    Code ( (Unknown Language)):
    1. #include <iostream>
    2. using namespace std;
    3.  
    4. void function1(int &a, int &b);
    5. void function2(int &a, int &b);
    6. void function3(int &a, int &b);
    7. void function4(int &a, int &b);
    8.  
    9. int main()
    10. {
    11.     int number1 = 1, number2 = 2;
    12.     function4(number1,number2);
    13.     return 0;
    14. }
    15.  
    16. void function1(int &a, int &b)
    17. {
    18.     cout << "This is function 1 printing out the value of a and b: " << a << b << endl;
    19. }
    20.  
    21. void function2(int &a, int &b)
    22. {
    23.     cout << "This is function 2 printing out the value of a and b: " << a << b << endl;
    24. }
    25.  
    26. void function3(int &a, int &b)
    27. {
    28.     cout << "This is function 3 printing out the value of a and b: " << a << b << endl;
    29. }
    30.  
    31. void function4(int &a, int &b)
    32. {
    33.     int number = 2;
    34.     void (*ptr[4])(int &, int &) = {function1,function2,function3};
    35.     (*ptr[number])(a,b);
    36. }
    37.  
    But when i try do the same thing using a class test 3 like this:

    Code ( (Unknown Language)):
    1.  
    2. #include <iostream>
    3. using namespace std;
    4.  
    5. class test3
    6. {
    7. public:
    8.     void function1(int &a, int &b);
    9.     void function2(int &a, int &b);
    10.     void function3(int &a, int &b);
    11.     void function4(int &a, int &b);
    12. };
    13.  
    14. int main()
    15. {
    16.     int number = 2,number1 = 3,number2 = 5;
    17.     test3 test;
    18.     test.function4(number,number1);
    19.        
    20.     return 0;
    21. }
    22. void test3::function1(int &a, int &b)
    23. {
    24.     cout << "This is function 1 printing out the value of a and b: " << a << b << endl;
    25. }
    26.  
    27. void test3::function2(int &a, int &b)
    28. {
    29.     cout << "This is function 2 printing out the value of a and b: " << a << b << endl;
    30. }
    31.  
    32. void test3::function3(int &a, int &b)
    33. {
    34.     cout << "This is function 3 printing out the value of a and b: " << a << b << endl;
    35. }
    36.  
    37. void test3::function4(int &a, int &b)
    38. {
    39.     int number = 2;
    40.     void (*ptr[4])(int &, int &) = {test3::function1,test3::function2,test3::function3};
    41.     (*ptr[number])(a,b);
    42. }
    Code ( (Unknown Language)):
    1. I get the error message:
    2. 1>------ Build started: Project: test3, Configuration: Debug Win32 ------
    3. 1>Compiling...
    4. 1>Test3.cpp
    5. 1>z:\college\year2\programming\programs\test3\test3\test3.cpp(39) : error C2440: 'initializing' : cannot convert from 'overloaded-function' to 'void (__cdecl *)(int &,int &)'
    6. 1>        None of the functions with this name in scope match the target type
    7. 1>z:\college\year2\programming\programs\test3\test3\test3.cpp(39) : error C2440: 'initializing' : cannot convert from 'overloaded-function' to 'void (__cdecl *)(int &,int &)'
    8. 1>        None of the functions with this name in scope match the target type
    9. 1>z:\college\year2\programming\programs\test3\test3\test3.cpp(39) : error C2440: 'initializing' : cannot convert from 'overloaded-function' to 'void (__cdecl *)(int &,int &)'
    10. 1>        None of the functions with this name in scope match the target type
    11. 1>Build log was saved at "file://z:\College\Year2\Programming\Programs\test3\test3\Debug\BuildLog.htm"
    12. 1>test3 - 3 error(s), 0 warning(s)
    13. ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
    14.  
    Clearly i am doing something wrong. Could someone please tell me what i am doing wrong or how i can use function pointer arrays in this manner, thanks!
     
    Last edited: Sep 4, 2008
  2. mentaaal

    Thread Starter Senior Member

    Oct 17, 2005
    451
    0
    Hey again guys, well after A LONG time searching the net, i found this:
    http://www.codeproject.com/KB/cpp/FastDelegate.aspx and found out how to do what i was trying to do and wow it is a cumbersome thing to do!
    Anyone know what the purpose of this is: "test3 *x = new test3;"
    I hope this helps anyone else who was curious about member function pointers. Although my research into this command has caused me more confusion that before i started!



    Code ( (Unknown Language)):
    1. #include <iostream>
    2. using namespace std;
    3.  
    4. class test3
    5. {
    6. public:
    7.     void function1(int &, int &);
    8.     void function2(int &, int &);
    9.     void function3(int &, int &);
    10.     void function4(int &, int &);
    11.     };
    12.  
    13. int main()
    14. {
    15.     int number = 2,number1 = 3,number2 = 5;
    16.     test3 test;
    17.     test.function4(number,number1);
    18.        
    19.     return 0;
    20. }
    21. void test3::function1(int &a, int &b)
    22. {
    23.     cout << "This is function 1 printing out the value of a and b: " << a << b << endl;
    24. }
    25.  
    26. void test3::function2(int &a, int &b)
    27. {
    28.     cout << "This is function 2 printing out the value of a and b: " << a << b << endl;
    29. }
    30.  
    31. void test3::function3(int &a, int &b)
    32. {
    33.     cout << "This is function 3 printing out the value of a and b: " << a << b << endl;
    34. }
    35.  
    36. void test3::function4(int &a, int &b)
    37. {
    38.     int number = 2;
    39.     void (test3::*ptr[4])(int &, int &) = {&test3::function1,&test3::function2,&test3::function3};
    40.     test3 *x = new test3;
    41.     (x->*ptr[number])(a,b);
    42. }
    From what i have managed to glean from college notes, the new function is to use the cpu's heap. But what i dont understand is why must using member function pointers be so painful? Also why must the address operator be used when defining the function pointer whereas is can be omitted when not using classes?
     
    Last edited: Sep 5, 2008
  3. Mark44

    Well-Known Member

    Nov 26, 2007
    626
    1
    It looks like you figured this out before I got a chance to reply. I tried a number of things before making the realization that, since the functions were now class members, you should create an instance of the class in order to get at them rather than merely get their addresses.

    To answer your question about the purpose of
    Code ( (Unknown Language)):
    1.  
    2. test3 *x = new test3;
    3.  
    it gives you a pointer to an instance of your class, and you can use the pointer to get at any member functions, using the class member dereference operator ->. E.g., you can now call function1, say, this way:
    Code ( (Unknown Language)):
    1.  
    2. x->function1(a, b);
    3.  
    The new operator gives you a chunk of memory from the heap (not the CPU heap -- there's no such thing that I'm aware of), as opposed to the stack, which is used for parameter passing (often) and local variables, among other uses.

    Your final question was about why you had to use the address-of operator when defining the function pointer. You're actually using it not to define the function pointer array, but in the things that you're initializing the array with. You can actually use the address-of operator in both your examples (i.e., the non-class example and the class example). In the non-class example, the compiler is smart enough to figure out that function1 should be treated as the address of a function, even without a preceding &. (BTW, the address of a function is the address of the start of its code.) Apparently, when you're working with classes, you need to give the compiler a bit more information.

    Hope that helps.
    Mark
     
  4. mentaaal

    Thread Starter Senior Member

    Oct 17, 2005
    451
    0
    Hey again Mark, haha its not like its your job to reply to all my questions (but i am really thankful for all the help you've given me in the past) yeah i dont really even know what a heap is to be honest with you.. just a one liner in my notes really.

    What do you mean by creating an instance of the class in
    test3 *x = new test3;
    I've never heard any mention of an instance of a class before. I suppose that this is a more advanced area of programming and i probably have yet to be introduced to it formally.

    What you said here is interesting: x->function1(a, b); This appears to have removed the need of typing: test3::function1(a,b); But if member functions can call other member functions easily enough why is it that when a pointer is used an instance has to be created. Going to all this hastle seems to remove all of the implied simplicity of pointers. (Although there must be more practical uses that i am not yet aware of like callback functions as i was reading in that link i posted)

    Cheers Mark
     
  5. Mark44

    Well-Known Member

    Nov 26, 2007
    626
    1
    Yeah, now we're starting to talk about object-oriented programming (OOP). To get you onto some familiar ground (I hope), when your program uses structs that you define, you first have to provide a sort of template for the struct, and then create a variable of that type. Simply defining the struct (template) doesn't cause the compiler to do anything in the way of allocating space and so on.

    Similarly, when you define a class, (in C++ the only difference between a struct and a class is in the default access specifier--public for struct members and private for class members), the class definition is a template that shows the compiler how to lay out variables of this type, if you actually get around to creating such variables.

    The code above creates a variable named x, of type test3. In the terminology usually used, x is an instance of the test3 class. Instances of classes can be created on the stack (e.g., local variables of a function, function parameters) or on the heap, using the new operator.

    If x is a member of the same class as function1, then you don't need to qualify x (i.e., you don't need test3::function1) with its class name. I'm reasonably sure that this statement is true.

    The hastle is intentional. One of the reasons for classes is to limit access to class members to other class members and friends of the class. Of course, if you make all the class members public, then you aren't limiting access at all, but then, that's your choice as the designer of the class.

    C doesn't have the concept of access at all, so if you have the address of a function and you declare a suitable function pointer, you can call that function through the pointer. In C++, however, you should not be able to access to everything in a class instance merely by having the address of an instance of that class. The public, protected, and private access specifiers in a class permit the designer of the class to provide a set of functions (aka methods) that anyone can use (the public ones), a set of methods that can be used only by certain classes (protected), and a set of internal methods that can be used only by other members of the class (private). This is a way to ensure some security over who can use what. So the choice is ease of use/no security vs. more difficult to use/some measure of security.

    Make sense?

    BTW, yes, I do spend a fair amount of time answering your questions, but I don't mind, since you ask good questions and it's clear that you have done some digging on your own.

    Mark
     
  6. mentaaal

    Thread Starter Senior Member

    Oct 17, 2005
    451
    0
    Ok i have read your reply 5 times in an attempt to ensure these next questions dont sound stupid:

    You said: "Yeah, now we're starting to talk about object-oriented programming (OOP). To get you onto some familiar ground (I hope), when your program uses structs that you define, you first have to provide a sort of template for the struct, and then create a variable of that type. Simply defining the struct (template) doesn't cause the compiler to do anything in the way of allocating space and so on." and i understand what you're saying but is instantiating an object of the class in "
    not doing just that? When the object test is made
    doesnt memory get allocated for the functions?

    In my class definition, all of the
    member functions are declared as public... so.. access is still prohibited because the pointer *ptr
    was not a friend of the class until the member *x was instantiated and called the pointer *ptr.
    Yeah i can see what you're saying here and it makes more sence now. Thanks!

    I can imagine i will treat the concept of access with alot more respect after making larger programs and they are easier to debug as a result.
     
  7. mentaaal

    Thread Starter Senior Member

    Oct 17, 2005
    451
    0
    Ah yes duh greg! What you're saying makes perfect sence now when you consider what a pointer is. Merely an address to something else and i wasnt pointing it to the object but the member functions. Which is why they needed to be called by the friend: *x.

    Thanks again i get it now!
     
  8. Mark44

    Well-Known Member

    Nov 26, 2007
    626
    1
    In order: 1)yes. The line of code above creates an instance (test) of the test3 class. The template that I referred to is the code that defines the layout of test3 that looks like this:
    Code ( (Unknown Language)):
    1.  
    2. class test3
    3. {
    4.     void function1();
    5.     etc. ...
    6. };
    7.  
    The class definition doesn't allocate any storage.
    2) Yes, but probably not the way you might be thinking. When you create an instance of a class, space is allocated for data members (one byte for char variables, four bytes for ints and floats, eight bytes for doubles), but the memory allocated for each member function is whatever is required for a pointer. IOW, a class instance doesn't contain the code for a member function--just a pointer to the code.
     
  9. mentaaal

    Thread Starter Senior Member

    Oct 17, 2005
    451
    0
    One interesting thing to note about member function pointers is a member containing a member function pointer cannot be called from a contructor. as it causes a stack overflow error, presumably because the object needs to be instantiated first?
     
  10. Mark44

    Well-Known Member

    Nov 26, 2007
    626
    1
    I don't follow what you're saying in the first sentence, but if you're getting a stack overflow, I suspect there is some circular logic happening. You might be able to confirm your conclusion by single-stepping through your constructor's code. For a stack overflow, there must be a slew of objects (class instances) being created as a result of calling through the function pointer in the constructor.
     
  11. mentaaal

    Thread Starter Senior Member

    Oct 17, 2005
    451
    0
    Yup, i understand why this is happening, when I use the constructor in the manner below, it calls function4 which creates an instance of the class which uses the constructor (i'm guessing) which calls function4 again which makes a loop, hence the stack overflow.

    Code ( (Unknown Language)):
    1. #include <iostream>
    2. using namespace std;
    3.  
    4. class test3
    5. {
    6. public:
    7.     test3(int a = 1,int b = 2);
    8.     void function1(int &, int &);
    9.     void function2(int &, int &);
    10.     void function3(int &, int &);
    11.     void function4(int &, int &);
    12.     };
    13.  
    14. int main()
    15. {
    16.     int number = 2,number1 = 3,number2 = 5;
    17.     test3 test(number,number1);
    18.     return 0;
    19. }
    20.    
    21. void test3::function1(int &a, int &b)
    22. {
    23.     cout << "This is function 1 printing out the value of a and b: " << a << b << endl;
    24. }
    25.  
    26. void test3::function2(int &a, int &b)
    27. {
    28.     cout << "This is function 2 printing out the value of a and b: " << a << b << endl;
    29. }
    30.  
    31. void test3::function3(int &a, int &b)
    32. {
    33.     cout << "This is function 3 printing out the value of a and b: " << a << b << endl;
    34. }
    35.  
    36. void test3::function4(int &a, int &b)
    37. {
    38.     int number = 2;
    39.     void (test3::*ptr[4])(int &, int &) = {&test3::function1,&test3::function2,&test3::function3};
    40.     test3 *x = new test3;
    41.     (x->*ptr[number])(a,b);
    42. }
    43.  
    44. test3::test3(int a,int b)
    45. {
    46.     test3::function4(a,b);
    47. }
    So i guess what i should have said is: Dont be silly like me and call a function from a constructor which creates an instance of the class!
     
  12. Mark44

    Well-Known Member

    Nov 26, 2007
    626
    1
    Bingo. You guess right.
     
Loading...