Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static function needing to deal with members of a C++ class

Tags:

c++

class

static

I have to make some kind of bridge between two pieces of software, but am facing an issue I don't know how to deal with. Hopefully someone will have interesting and (preferably) working suggestions.

Here is the background : I have a C++ software suite. I have to replace some function within a given class with another function, which is ok. The problem is that the new function calls another function which has to be static, but has to deal with members of the class. This is this second function which is making me mad.

If the function is not static I get the following error :

error: argument of type ‘void (MyClass::)(…)’ does not match ‘void (*)(…)’

If I set it to static I get either the following error :

error: cannot call member function ‘void
MyClass::MyFunction(const double *)’ without object

or

error: ‘this’ is unavailable for static member functions

depending on if I use or not the "this" keyword ("Function()" or "this->Function()").

And finally, the class object requires some arguments which I cannot pass to the static function (I cannot modify the static function prototype), which prevents me to create a new instance within the static function itself.

How would you deal with such a case with minimal rewriting ?

Edit : Ok, here is a simplified sample on what I have to do, hoping it is clear and correct :

// This function is called by another class on an instance of MyClass
MyClass::BigFunction()
{

    …
// Call of a function from an external piece of code, 
// which prototype I cannot change
    XFunction(fcn, some more args);
    …

}


// This function has to be static and I cannot change its prototype,
// for it to be passed to XFunction.  XFunction makes iterations on it
// changing parameters (likelihood maximization) which do not appear 
// on this sample
void MyClass::fcn(some args, typeN& result) 
{

// doesn't work because fcn is static
    result = SomeComputation();

// doesn't work, for the same reason
    result = this->SomeComputation(); 

// doesn't work either, because MyClass has many parameters
// which have to be set
    MyClass *tmp = new MyClass();
    result = tmp->SomeComputation();

}
like image 389
Skippy le Grand Gourou Avatar asked Feb 24 '12 11:02

Skippy le Grand Gourou


People also ask

What is static member function in C?

The static member functions are special functions used to access the static data members or other static member functions. A member function is defined using the static keyword. A static member function shares the single copy of the member function to any number of the class' objects.

Can we use static for function in C?

Static functions in C are functions that are restricted to the same file in which they are defined. The functions in C are by default global. If we want to limit the scope of the function, we use the keyword static before the function.

Why is a static member function required?

By declaring a function member as static, you make it independent of any particular object of the class. A static member function can be called even if no objects of the class exist and the static functions are accessed using only the class name and the scope resolution operator ::.

How is the static member function of a class called?

A static function can only access other static variables or functions present in the same class. Static member functions are called using the class name. Syntax- class_name::function_name( )


2 Answers

Pointers to non-static member functions are a bit tricky to deal with. The simplest workaround would just be to add an opaque pointer argument to your function which you can then cast as a pointer to 'this', then do what you need with it.

Here's a very simple example:

void doSomething(int (*callback)(void *usrPtr), void *usrPtr)
{
    // Do stuff...
    int value = callback(usrPtr);
    cout << value << "\n";
}

class MyClass
{
public:
    void things()
    {
        value_ = 42;
        doSomething(myCallback, this);
    }

private:
    int value_;

    static int myCallback(void *usrPtr)
    {
        MyClass *parent = static_cast<MyClass *>(usrPtr);
        return parent->value_;
    }
};

int main()
{
    MyClass object;
    object.things();
    return 0;
}

In this example myCallback() can access the private value_ through the opaque pointer.

If you want a more C++-like approach you could look into using Boost.Function and Boost.Bind which allow you to pass non-static member functions as callbacks:

void doSomething(boost::function<int ()> callback)
{
    // Do stuff...
    int value = callback();
    cout << value << "\n";
}

class MyClass
{
public:
    void things()
    {
        value_ = 42;
        doSomething(boost::bind(&MyClass::myCallback, this));
    }

private:
    int value_;

    int myCallback()
    {
        return value_;
    }
};

int main()
{
    MyClass object;
    object.things();
    return 0;
}

If you really can't change the function prototype you could use a global pointer, but that opens up all sorts of issues if you will ever have more than one instance of your class. It's just generally bad practice.

class MyClass;
static MyClass *myClass;

void doSomething(int (*callback)())
{
    // Do stuff...
    int value = callback();
    cout << value << "\n";
}

class MyClass
{
public:
    void things()
    {
        value_ = 42;
        myClass = this;
        doSomething(myCallback);
    }

private:
    int value_;

    static int myCallback()
    {
        return myClass->value_;
    }
};

int main()
{
    MyClass object;
    object.things();
    return 0;
}
like image 57
spencercw Avatar answered Sep 21 '22 03:09

spencercw


Following spencercw's suggestion below the initial question I tried the "static member variable that you set to point to this" solution (the global variable would have been tricky and dangerous within the context of the software suite).

Actually I figured out there was already something like this implemented in the code (which I didn't write) :

static void*          currentObject;

So I just used it, as

((MyClass*)currentObject)->SomeComputation();

It does work, thanks !!!

like image 26
Skippy le Grand Gourou Avatar answered Sep 22 '22 03:09

Skippy le Grand Gourou