Home > database >  how to detect what struct a function is being called from
how to detect what struct a function is being called from

Time:12-14

The title is confusing, i tried my best to explain it in a few words but i failed. Here is a better explenation of my problem.

Lets say there's a struct named Object with a bool variable named _active and a function named SetActive().

typedef struct Object
{
    bool _active;
    void (*SetActive)(bool)
} Object;

Object someObject;
Object someOtherObject;

void SetActive(bool set)
{
    /*
    if function is being called from someObject, then
    someObject._active = set
    if function is being called from someOtherObject, then
    someOtherObject._active = set
    */
}

(This is an example)
I want SetActive() to set _active of the struct its being called from to set
For example when i call structname.SetActive(true), structname._active = true
How do i do something like this?

CodePudding user response:

void (*SetActive)(bool); is a pointer to a free function. It has no association with any particular object.

In C it's pretty common to supply the object as the first or last argument to the functions acting as member functions. This is needed because C doesn't have actual member functions. To make the association clear to other programmers reading the code, you can prepend all acting "member functions" with the name of the type each function acts upon.

It could look like this:

#include <stdbool.h>
#include <stdlib.h>

typedef struct Object Object;
struct Object {
    bool _active;
};

Object *Object_create() {
    Object *obj = malloc(sizeof *obj);
    
    if(obj) {
        // provide some default init values
        *obj = (Object){ ._active = false };
    }
    return obj;
}

void Object_destroy(Object *obj) {
    free(obj);
}

void Object_SetActive(Object *obj, bool set) {
    obj->_active = set;
}

int main(void) {
    Object *obj = Object_create();
    
    Object_SetActive(obj, true);

    Object_destroy(obj);
}

CodePudding user response:

If you really really want to have a poor man OOP, you can do it. But why not switching to a more friendly language?

Basically you would include a function pointer in a struct, iif you plan to override that function in a subclass. This is needed only for polymorphism. In that case you will probably need also a polymorphic destructor for your class. The problem is that you get pointers to these polymorphic functions in every instance of your objects, so better alternatives are required (vtables, pointer to class CPython style, ...).

The bad news is that now you need to specify the object to access the function pointer and to pass it to the function itself. Which really requires some syntax sugar.

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>

typedef struct Object Object;
struct Object {
    bool active_;
    void (*SetActive)(Object *this, bool status); // This is a virtual method
    void (*Destruct)(Object *this); // You will need this for polymorphism
};
void Object_SetActive(Object *this, bool status);
void Object_Destructor(Object *this);

void Object_Constructor(Object *this) { // Default constructor
    this->active_ = false;
    this->SetActive = Object_SetActive;
    this->Destruct = Object_Destructor;
}
void Object_Destructor(Object *this) {
    // Nothing to be done here, but maybe when subclassing?
}
void Object_SetActive(Object *this, bool status) {
    this->active_ = status;
}

int main(void)
{
    Object someObject; 
    Object_Constructor(&someObject);
    Object someOtherObject;
    Object_Constructor(&someOtherObject);

    someObject.SetActive(&someObject, true);
    someOtherObject.SetActive(&someOtherObject, false);

    printf("someObject.active_ = %s\n", someObject.active_ ? "true" : "false");
    printf("someOtherObject.active_ = %s\n", someOtherObject.active_ ? "true" : "false");

    someObject.Destruct(&someObject);
    someOtherObject.Destruct(&someOtherObject);

    return 0;
}

If you want to waste some time with OOP in C, with macro abuse, you can read this post.

Warning: I don't want to be held responsible for nausea or vomiting caused by reading that post.

With respect to Ted Lyngmo's answer, I'm constructing and destructing already allocated objects. This would need also some new and delete clones.

  • Related