Sign in to follow this  
Sabonis

Function Pointers in c++

Recommended Posts

Hi all, I am building an error logging system for my program and I have run into a few problems. First of all, I am programming in the Linux environment using g++ 4.1.2 in ubuntu. I wrote a class called ErrorLogger that has a public member function called LogError. All of my other classes have a function pointer so that I can allow them access to LogError. So what my intention is to not integrate ErrorLogger into the rest of my classes because if I changed ErrorLogger it would become a headache to change them all. Here is what I am doing -ErrorLogger object is stored globally (for now) -I instantiate a class object from my library and set the function pointer to ErrorLogger::LogError ErrorLogger ErrLogr; int main() { ClassA NewObject; NewObject.SetErrorFunc(&ErrorLogger::LogError); NewObject.ErrorFuncPointer(arg1,arg2); ..... } The compiler complains : invalid use of non-static member function ErrorLogger::LogError How can I make it so that the global ErrLogr member function LogError is specifically called instead of just the generic function?

Share this post


Link to post
Share on other sites
I don't know how C++ does method pointers (though, it's sure to be weird).

You could try doing it the Java-approved way. Instead of passing a function pointer, pass an object which implements an HandleError interface. Then, you can simply call the virtual HandleError method... which will either be your old method or your new one.

Share this post


Link to post
Share on other sites
Why do you only pass the function as an argument, when it would make just as much sense to pass the logger itself?

Ultimately, your problem comes from trying to use a member function pointer as if it were a normal function pointer. Check your favourite book, tutorial or search engine for the massive and unavoidable difference between the two.

Share this post


Link to post
Share on other sites
Thanks, ToohrVyk

The reason why I do not pass the logger itself is that I don't want to have to integrate the error logger into all of my classes. If I were to make a change to a function name or write a new logger, I don't want to have to go through all of the classes to change the implementation. I would rather just call a function through a generic function pointer with a set amount and type of arguments.
Thanks again, I am totally clear on the difference between the two, just wasn't sure about the syntax.

Thanks for the reference Sneftel, it has some good info with member function pointers that I didn't have in my book. I will try this again using different syntax.

Share this post


Link to post
Share on other sites
In that case, you can use a (smart) pointer to a virtual base class that offers the logger functionality. Then you only need to recompile the clients if the logger interface changes, which you'd have to do anyway with function pointers.

Share this post


Link to post
Share on other sites
Couldn't I just also use a namespace?
I know those can get kind of hairy but that might make things a little easier to access.

I have a feeling that not many people would support using namespaces..

Share this post


Link to post
Share on other sites
As far as maintenance, it should be identical to use either a logger interface, or a typedef'd function pointer - IF you create a header file for such a thing that does not include other, unrelated information.

IE, if you have a header ILogger.h with a class ILogger { public: void LogError(/*parameters*/); };

or a file LogErrorFunc.h with typdef void (*LogErrorFunc)(/*parameters*/);

each should be just as resistent to future changes as each other - with 1 exception. Its just a decision if you like someone having the option of implementing logging as a standalone non-member function (like for instance a C client, or other language that can export C functions), or if you like them having the option of writing their logger class to contain additional state useful to logging (such as filters) without having to resort to global / static tricks.

I personally use the ILogger method in my system, because nearly all usefull loggers have some basic state it might keep cached when appropriate (for instance a file based logger has a path or file, a database logger a connection, etc).

Good luck.

Share this post


Link to post
Share on other sites
Quote:
each should be just as resistent to future changes as each other - with 1 exception. Its just a decision if you like someone having the option of implementing logging as a standalone non-member function (like for instance a C client, or other language that can export C functions), or if you like them having the option of writing their logger class to contain additional state useful to logging (such as filters) without having to resort to global / static tricks.


In the case that compatibility with clients using C is an issue I would go with the function version but #ifdef it to use boost.function when in c++ so that c++ clients can use boost.bind or std::mem_fn and std::bind1st/std::bind2nd to associate state with it.

#ifdef __cplusplus
#include <boost/function.hpp>
typedef boost::function<void (/* Params */)> error_log_function;
#else
typedef void (*error_log_function)(/* Params */);
#endif

Share this post


Link to post
Share on other sites
You could consider using a thin adaptor class as the interface to your logger.

template <typename ARG1_TYPE, typename ARG2_TYPE>
class ErrorLogInterface{
public:
virtual void operator()(ARG1_TYPE arg1, ARG2_TYPE arg2) = 0;
};

template <typename LOGGER_TYPE, typename ARG1_TYPE, typename ARG2_TYPE>
class ErrorLogAdaptor : public ErrorLogInterface<ARG1_TYPE, ARG2_TYPE>{

public:
typedef void (LOGGER_TYPE::*pointer)(ARG1_TYPE arg1, ARG2_TYPE arg2);


private:
pointer p;


public:
ErrorLogAdaptor(pointer _pf):p(_pf){}
void operator()(ARG1_TYPE arg1, ARG2_TYPE arg2){
p(arg1,arg2);
}

};




Usage: pass the address of an ErrorLogAdaptor to each class that can access the logger. In each of these classes, store it in an ErrorLogInterface pointer and access it through this pointer. You declare a single instance of your ErrorLogAdaptor as in

ErrorLogAdaptor<ErrorLogger,ErrorLogger::arg1_type,ErrorLogger::arg2_type> ErrLogr(&ErrorLogger::LogError);

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this