Solved

Passing functions as arguments to other functions

Posted on 2000-03-01
12
210 Views
Last Modified: 2010-05-18
Ok, the subject kind of sais it all, what i'm trying to do is pass a class function to another classe's function, i've tried this way and it's failing:

typedef void (*rec_function_ptr)(CString);
typedef void (*close_function_ptr)(int);

to define function passing, then the function that takes functions was defined as follows:

CConnectSocket(rec_function_ptr onReceiveFunc, close_function_ptr onCloseFunc);

and the functions i'm passing are:

  void ConnectionClose(int errCode);
  void ParseData(CString str);


Now when i try to compile i get this error

error C2664: 'CConnectSocket::CConnectSocket' : cannot convert parameter 1 from 'void (class CString)' to 'void (__cdecl *)(class CString)


can anyone pleaseee tell me what i'm doing wrong?! i've been trying to figure this thing out for over an hour now :(

Thank you
0
Comment
Question by:gkanaan
  • 8
  • 4
12 Comments
 
LVL 22

Expert Comment

by:nietod
ID: 2575139
>> what i'm trying to do is pass a class function
>> to another classe's function
Its hard to see that in the code you produced, but if that is the case, then the code is wrong.  

A pointer to class's non-static member function has a special type, it is called a "pointer-to-member" and it may be represented in a different way than other pointers.  The syntax for using it is also a little different--for good reason.

continues
0
 
LVL 22

Expert Comment

by:nietod
ID: 2575150
Lets take the first example

typedef void (*rec_function_ptr)(CString);

say you have a non-static ember function that takes a CString as a data member like

class Cls
{
public:
   void F1(CString);
};

You would probably say that the funciton F1 takes only one parameter, right?   Well actually no, it takes two.  There is a 2nd parameter that is "hidden"  i.e. you don't declare it.  It is the "Cls" object that function is suppoed to work with.  This parameter is passed as the "this" pointer.

Why do I mention this?  well it means that a non-member function declared like

void F2(CString);

is inheritently different than the member function, this is because it does not have that hidden parameter.

continues
0
 

Author Comment

by:gkanaan
ID: 2575153
Yes i've looked around some previous similar questions and found a solution however since i'm kind of a beginner in C++ i got lost reading it, it seems quite complicated if i want to pass member function as an argument from 2 different classes, so i'm dropping the idea for now, thanks anyway...
0
 
LVL 22

Expert Comment

by:nietod
ID: 2575169
Since the member and non-member functions are inheriently different, the pointers to them are also inhierently different and are not interchangable.  a pointer to a member function must be declared as in this example.

class Cls
{
   int Add(int i1,int i2) { return i1 + i2 };
   int Subd(int i1,int i2) { return i1 - i2 };
   int Abs(int i) { return i <0? -1*i:i; };
}

// member function pointer typedef.  Not
// necessary, except for readability.
typedef int (Cls::*MbrFunPtrTyp)(int,int);
// This type is a pointer to a member function of Cls that
// takes 2 ints as parameters and returns a int.  
// Thus this type of pointer can point to Add() or Sub()
// but not to Abs().

Now the when the member function pointer is used to call the member function and object must be supplied for the function to work with.  This is the "this" object.  So member functions are called with a unique sintax as follows.

// Declare and use a pointer of this type.
MbrFunPtrTyp FunPtr = &Cls::Add; // make pointer to add function.
Cls C;                             // Declare object of the class
Cls *CPtr = &C;            // Declare pointer to object of the class.

int R1 = (C.*FunPtr)(1,2); // Add 1 and 2 using a Cls object.
int R2 = (CPtr->*FunPtr)(1,2); // Add 1 and 2 using a pointer to a Cls object.

FunPtr = &Cls::Sub; // Make pointer to Sub function.

int R3 = (C.*FunPtr)(1,2); // Subtract1 and 2 using a Cls object.
int R4 = (CPtr->*FunPtr)(1,2); // Subtract 1 and 2 using a pointer to a Cls object.

Note that the functions that the pointer-to-member pointer will be used with must have the same signature.  To be precise they must:

1. be members of the same class.
2. have the same parameters.
3. have the same return value
4. Have the same calling convention.  (in other words, all must be virtual or none must be virtual.  all must be cdecl, or all must be extern "C" etc.)

Thus the example above the function pointer could be used with Add() and Sub(), but not with Abs().  You could define a seperate function pointer type that could be used with Abs() and other member functions of Cls that have the same parameters and signature etc.

Let me know if you have any questions
0
 
LVL 22

Expert Comment

by:nietod
ID: 2575174
>> so i'm dropping the idea for now, thanks anyway...
Huh?   I've answered the question.  Now it is a little late to drop it!
0
 

Author Comment

by:gkanaan
ID: 2575186
Ok sorry i didn't know you were answering all, i only had read your first comment, however, what you're explaining is how to call a Specific class' function, what i need is to call a function in an abstract class, say i have (not C++ specific format, just to be fast)

Class B {
  void funcB(CString a);
}

Class A {
  void funcA(CString a);
}

Class C {
  C(func_ptr fptr);
  void example();
}

As you see here the class C should be able to take any function if it's from class A or B as long as it has the same signature (that is what i'm trying to accomplish)...
do you get my point?  
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 22

Accepted Solution

by:
nietod earned 150 total points
ID: 2575234
That is logically impossible.  it is not a matter of syntax it is that that sort of design makes no sense.  

Non static member functions have these hidden parameters that they may work on.  Right?  Well can you specify the correct type of parameter if the parameter type changes depending on the function to be called?  seee the problem.  

Now if these functions don't need to work on the "hidden parameter"   i.e. if then don't need to access any of the classes data members or non-static functions.  Then you can just declare these functions as static members, like

class A
{
   static void FunctA(CString a)
};

In this case the functions will not be passed the extra hidden parameter.  That means all there functiosn will have the same signature (same parameters) and will act like ordinary functions.  That is, ordinary function pointers are used to call the functions.  None of the weird syntax above is needed.

Now that works only if the functions don't access the class's data members.  if they do, you have more trouble.  You can still make it work, but only by calling "interface functions"  These are ordinary functions  (i.e. non-member functions or static member functiosn (no hidden this parameter.)  These interface functions will then call the non-static member function using an object that they retreive  in some way, like as a parameter .  Like for example

class A
{
   void FunA(CString s); // non-static we ultimately want to call.
   static void Interface(void *ObjPtr,CString s) // static interface function.
   {
       A* ThisPtr = (A*)ObjPtr; // get object to be used.
       ObjPtr->FunA(s);  // Call the non-static
   };
};

See how this interface function gets an object to make the non-static call with.  In this case the object comes from the parameters.  It could come fom a global varaible or from a table or other source.  Then once it has the object, it makes the call using it.

Note that in the fucntion, the object pointer is passed using a void* pointer.  not a A* pointer.  This is so that the interface function has the same signature (parameters) as the interface functions of the other classes.  That way one pointer type can be used too call any of the interface functions.

Now this means that when you use this design, you must specify an object and an function pointer that work together.  i.e you can't specify the pointer to class B's interface function and a pointer to an object of class A.  That will cause unpredicatable behaviour.

Does that make sense?
0
 
LVL 22

Expert Comment

by:nietod
ID: 2576242
gkanaan,
  What is wrong?  I gave you two ways to accomplish what you wanted.  (depending on your needs.)
0
 

Author Comment

by:gkanaan
ID: 2576582
Yes thank you, i didn't read it last night because i was Very tired man, i just read the second option you gave and it seems quite logical and it should work, i'll try it...
Thanks
0
 
LVL 22

Expert Comment

by:nietod
ID: 2576648
Well you shouldn't grade a question until you have read it and all the discussion is finished.  The grade you give is permenantly stored in an expert's history.  I don't like get poor grades, especially after wroking so hard on a question.
0
 

Author Comment

by:gkanaan
ID: 2576663
i'm sorry i didn't pay attention i'm telling i wasn't quite awake, can i regrade in any way?
0
 
LVL 22

Expert Comment

by:nietod
ID: 2576695
Not now.  Just try to be more careful in the future.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
SetCurrentDirectory path limit 7 104
Compile GLUT with Visual Studio 2015 1 108
Dynamically allocate memory 9 56
Create a path if not exists 7 69
Errors will happen. It is a fact of life for the programmer. How and when errors are detected have a great impact on quality and cost of a product. It is better to detect errors at compile time, when possible and practical. Errors that make their wa…
Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…

919 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now