Получить указатель на функцию вызова структуры - PullRequest
3 голосов
/ 28 апреля 2011

Для текущего проекта я не могу использовать C ++ (к сожалению), только чистый C, и у меня возникает следующая проблема:

У меня есть 3 отличительные структуры, которые должны вызывать одно и то же имя функции, и я чувствую, что это более элегантно, чем ниже, вместо того, чтобы создавать 3 разные функции для разных типов, как мне кажется, легче поддерживать их. Как я могу получить указатель, который вызывает функцию? По сути, то, что я пытаюсь воспроизвести, в основном похоже на "this" в C ++ или self (в Obj-C), есть ли в любом случае, я могу сделать это в простом C?

[test.h]

enum
{  
    TYPE_A = 0,  
    TYPE_B = 1,  
    TYPE_C = 2  
};

typedef struct  
{  
    char type;    
    void ( *GetType )( void );  
    // Some other data different than the other struct  
}A;  


typedef struct  
{  
    char type;  
    void ( *GetType )( void );  
    /* Some other data different than the other struct */  
}B;  


typedef struct  
{  
    char type;  
    void ( *GetType )( void );  
    // Some other data different than the other struct  
} C;

A *create_a( void );

B *create_b( void );

C *create_c( void );

void GetType( void );

[test.c]

A *create_a( void )  
{  
    A *a = ( A * ) calloc( 1, sizeof( A ) );  
    a->type = TYPE_A;  
    a->GetType = GetType;  
    return a;  
}

B *create_b( void )  
{  
    B *b = ( B * ) calloc( 1, sizeof( B ) );  
    b->type = TYPE_B;  
    b->GetType = GetType;  
    return b;  
}


C *create_c( void )
{  
    C *c = ( C * ) calloc( 1, sizeof( C ) );  
    c->type = TYPE_C;  
    c->GetType = GetType;  
    return c;  
}


void GetType( void )  
{  
    printf("How to get the pointer that call this function to retrieve the type?");  
}  

[main.c]

int main (int argc, const char * argv[])  
{  
    A *a = create_a();  
    B *b = create_b();  
    C *c = create_c();  

    a->GetType();  
    b->GetType();  
    c->GetType();  

    return 0;  
}

Ответы [ 4 ]

0 голосов
/ 28 апреля 2011

Из того, что я понял, ваш вопрос: «Вы просто хотите получить значение поля типа в структуре в функции GetType». Это правильно? Если да, вы можете сделать это следующим образом:

enum
{  
    TYPE_A = 0,  
    TYPE_B = 1,  
    TYPE_C = 2  
};

typedef struct  
{  
    char type;    
    // Some other data different than the other struct  
}A;  


typedef struct  
{  
    char type;    
    /* Some other data different than the other struct */  
}B;  


typedef struct  
{  
    char type;  
    // Some other data different than the other struct  
} C;


A *create_a( void );

B *create_b( void );

C *create_c( void );

void GetType( void * );

[test.c]

  A *create_a( void )  
    {  
        A *a = ( A * ) calloc( 1, sizeof( A ) );  
        a->type = TYPE_A;  
        return a;  
    }

    B *create_b( void )  
    {  
        B *b = ( B * ) calloc( 1, sizeof( B ) );  
        b->type = TYPE_B;  
        return b;  
    }

    C *create_c( void )
    {  
        C *c = ( C * ) calloc( 1, sizeof( C ) );  
        c->type = TYPE_C;  
        return c;  
    }
#define GetType(x) (x->type)

[main.c]

int main (int argc, const char * argv[])  
{  
    A *a = create_a();  
    B *b = create_b();  
    C *c = create_c();  

    GetType(a);  
    GetType(b);  
    GetType(c);  

    return 0;  
}

Надеюсь, что это отвечает на ваш вопрос.

0 голосов
/ 28 апреля 2011

«this» следует указывать в качестве параметра для GetType (). Вот как на самом деле реализуются методы объекта. Более того, поскольку GetType должен иметь возможность взаимодействовать со всеми видами структур - структуры должны иметь похожий «базовый класс». например:

#include "stdio.h"

typedef enum
{  
TYPE_A = 0,  
TYPE_B = 1,  
TYPE_C = 2  
} my_class_type;

typedef struct  
{  
char type;    
my_class_type ( *GetType )( void* );  
}my_base;  

my_class_type my_base_GetType( void* my_base_ptr)  
{  
    return ((my_base*)my_base_ptr)->type;
}  

typedef struct  
{
    my_base base;
    // Some other data different than the other struct  
}A;  


typedef struct  
{  
    my_base base;
/* Some other data different than the other struct */  
}B;  


typedef struct  
{  
    my_base base;
// Some other data different than the other struct  
}C;

A *create_a( void )  
{  
A *a = ( A * ) calloc( 1, sizeof( A ) );  
a->base.type = TYPE_A;  
a->base.GetType = my_base_GetType;  
return a;  
}

B *create_b( void )  
{  
B *b = ( B * ) calloc( 1, sizeof( B ) );  
b->base.type = TYPE_B;  
b->base.GetType = my_base_GetType;  
return b;  
}


C *create_c( void )
{  
C *c = ( C * ) calloc( 1, sizeof( C ) );  
c->base.type = TYPE_C;  
c->base.GetType = my_base_GetType;  
return c;  
}




int main(int argc, char* argv[])
{
    A *a = create_a();  
    B *b = create_b();  
    C *c = create_c();  

    printf("%d\n",a->base.GetType(a));  
    printf("%d\n",b->base.GetType(b));  
    printf("%d\n",c->base.GetType(c));  
    return 0;
}

Этот пример реализует наследование и полиморфизм. Все структуры имеют одно и то же базовое ядро, и если вы хотите переопределить GetType (), просто измените указатель в базе. вы можете удерживать указатель на my_base и динамически разрешать тип.

0 голосов
/ 28 апреля 2011

Передайте это как обычный параметр (сначала, чтобы быть стандартным):

void GetType(void *this);
...
GetType(a); // instead of C++-style a->GetType

Было бы лучше иметь некоторый "базовый класс" (включая поле "тип типа"), в этом случаеуказатель будет "struct Base * this", а не "void * this").

Лично я всегда так иду.Вы можете добавить префикс для функций некоторого «класса» (например, Cl1_GetType).Это способ ОО-программирования на языке C. «Реальные виртуальные функции» через указатели функций также могут быть использованы, но это не такой распространенный случай.

0 голосов
/ 28 апреля 2011

Традиционный способ сделать это (например, в ядре UNIX) - использовать #define для синтаксического сахара:

#define GET_TYPE(X) ((X)->GetType((X)))

Конечно, если есть больше аргументов, он передает их какЧто ж.Указатели на функции обычно собираются в одну статическую структуру «ops», которая назначается при создании (вместо каждого отдельного указателя на функцию).Каждый вектор операций имеет соответствующую коллекцию #defines.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...