代码之家  ›  专栏  ›  技术社区  ›  claf

C中的默认构造函数

  •  26
  • claf  · 技术社区  · 16 年前

    有没有一种方法可以让C结构的用户类型(比如C++)有一个默认的构造函数?

    pthread_mutex )但我想知道,您是否可以在声明时填充结构的某些(或全部)字段。

    例如 pthread_互斥体 例如,我想

    pthread_mutex_t my_mutex;
    

    pthread_mutex_t my_mutex = PTHREAD_MUTEX_INITIALIZER;
    
    13 回复  |  直到 10 年前
        1
  •  41
  •   Tim    16 年前

    您可以创建使用指向结构的指针的初始值设定项函数。这是惯例。

    可怕的伪代码,在malloc或free上没有错误检查

    somestruct* somestruct_factory(/* per haps some initializer agrs? */)
    {
      malloc some stuff
      fill in some stuff
      return pointer to malloced stuff
    }
    
    
    void somestruct_destructor(somestruct*)
    {
      do cleanup stuff and also free pointer
      free(somestruct);
    }
    

    有人可能会来解释一些早期的C++预处理器/编译器如何在C.进行这一切。

        2
  •  21
  •   Reed    16 年前

    例如C++代码:

    class A {
      public:
        A() { a = 0; }
        int a;
    };
    
    int main() 
    {
      A b;
      A *c = new A;
      return 0;
    }
    

    等效C代码:

    struct A {
      int a;
    };
    
    void init_A_types(struct A* t)
    {
       t->a = 0;
    }
    
    int main()
    {
       struct A b;
       struct A *c = malloc(sizeof(struct A));
       init_A_types(&b);
       init_A_types(c);
       return 0;
    }
    

    函数“iNITAAYTYPE”作为构造函数将在C++中使用。

        3
  •  12
  •   plinth    16 年前

    结构的问题是,所有内容都是公共的,因此没有数据隐藏。

    我们可以解决这个问题。

    typedef struct t_ProcessStruct *t_ProcessHandle;
    
    extern t_ProcessHandle NewProcess();
    extern void DisposeProcess(t_ProcessHandle handle);
    
    typedef struct t_PermissionsStruct *t_PermissionsHandle;
    
    extern t_PermissionsHandle NewPermissions();
    extern void DisposePermissions(t_PermissionsHandle handle);
    
    extern void SetProcessPermissions(t_ProcessHandle proc, t_PermissionsHandle perm);
    

    然后创建一个包含如下定义的私有头文件:

    typedef void (*fDisposeFunction)(void *memoryBlock);
    
    typedef struct {
        fDisposeFunction _dispose;
    } t_DisposableStruct;
    
    typedef struct {
        t_DisposableStruct_disposer; /* must be first */
        PID _pid;
        /* etc */
    } t_ProcessStruct;
    
    typedef struct {
        t_DisposableStruct_disposer; /* must be first */
        PERM_FLAGS _flags;
        /* etc */
    } t_PermissionsStruct;
    

    然后在您的实现中,您可以执行如下操作:

    static void DisposeMallocBlock(void *process) { if (process) free(process); }
    
    static void *NewMallocedDisposer(size_t size)
    {
        assert(size > sizeof(t_DisposableStruct);
        t_DisposableStruct *disp = (t_DisposableStruct *)malloc(size);
        if (disp) {
           disp->_dispose = DisposeMallocBlock;
        }
        return disp;
    }
    
    static void DisposeUsingDisposer(t_DisposableStruct *ds)
    {
        assert(ds);
        ds->_dispose(ds);
    }
    
    t_ProcessHandle NewProcess()
    {
        t_ProcessHandle proc =  (t_ProcessHandle)NewMallocedDisposer(sizeof(t_ProcessStruct));
        if (proc) {
            proc->PID = NextPID(); /* etc */
        }
        return proc;
    }
    
    void DisposeProcess(t_ProcessHandle proc)
    {
        DisposeUsingDisposer(&(proc->_disposer));
    }
    

    重要的一点是 使结构安全和可初始化的工程模式。

        4
  •  8
  •   ConcernedOfTunbridgeWells    16 年前

    不,不是直接的。最接近的方法是编写一个函数,分配一个实例并填充一些字段。

        5
  •  5
  •   Johannes Schaub - litb    16 年前

    您可以编写一个返回C结构的函数:

    struct file create_file(int i, float f) {
        struct file obj = { i, f };
        // other code here...
        return obj;
    }
    

    如果你想知道在C中是否可以有“正常”的成员函数,那么,在某种程度上,你可以。我更喜欢对象作为第一个参数样式。将指向结构的指针作为第一个参数传递。通过这种方式,您可以使用多个函数来定义对象的接口:

    int file_get_integer(struct file *self) { return self->i; }
    float file_get_float(struct file *self) { return self->f; }
    

    如果您以这种风格编写,那么您最后得到的是一种抽象数据类型。我见过通过在C++中使用函数指针来模拟C++中的成员函数调用语法的人,然后做:

    obj.get_integer(&obj);
    

    linux内核使用它来定义文件系统驱动程序的接口。这是一种写作风格,一个人可能喜欢,也可能不喜欢。我不太喜欢它,因为我一直在为数据使用结构成员,而不是像流行的面向对象语言那样模拟成员函数调用。

        6
  •  3
  •   Aaron Digulla    16 年前

    基本上,C++创建包含方法地址的指针列表。此列表称为类定义(类定义中还有一些数据,但我们暂时忽略了这些数据)。

    typedef struct __class * class;
    typedef void (*ctor_ptr)(class);
    struct class {
        char * name;
        ctor_ptr ctor;
        ... destructor and other stuff ...
    }
    
    #define NEW(clz) ((struct something *)(((struct class *)clz)->ctor(clz)))
    

    现在,您可以通过为每个类创建“struct class”类型的结构来定义所拥有的类,然后调用其中存储的构造函数。这同样适用于析构函数等。

    如果需要实例的方法,则必须将它们放入类结构中,并在实例结构中保留指向类的指针:

    #define NEW_SOMETHING() ((struct something *)NEW(&something_definition))
    #define METHOD(inst, arg) ((struct something_class *)(((struct something *)inst)->clz)->method(inst, arg))
    

    NEW_SOMETHING 将使用存储在结构中的类定义创建“something”的新实例 something_definition . 方法将在此实例上调用“方法”。请注意,对于真正的代码,您需要检查它 inst 实际上是 something (比较类指针,诸如此类)。

    继承有点棘手,留给读者作为练习。

    如果您想看一个示例,请查看 glib (Gtk+项目的一部分)。

        7
  •  2
  •   Thomas Padron-McCarthy    16 年前

    如果是全局变量(初始化为零),则 能够 在某种程度上模拟一个无参数构造函数,方法是在其中包含一个“initialized”标志,然后让其他函数检查该标志,如果该标志为零,则初始化该结构。不过,我一点也不确定这是个好主意。

    而且,正如其他人指出的,你也可以用宏做一些可怕的事情。。。

        8
  •  2
  •   gnud    16 年前

    但在一篇评论中,您提到需要一个“默认构造函数”——我想您的意思是希望将一些(所有?)结构字段初始化为默认值。

    这是在C中使用一些编码约定完成的——函数、宏或混合。 我通常是这样做的--

    struct some_struct {
        int a;
        float b;
    };
    #define some_struct_DEFAULT { 0, 0.0f}
    struct some_struct *some_struct_create(void) {
        struct some_struct *ptr = malloc(sizeof some_struct);
        if(!ptr)
            return ptr;
    
        *ptr = some_struct_DEFAULT;
        return ptr;
    }
    // (...)
    struct some_struct on_stack = some_struct_DEFAULT;
    struct some_struct *on_heap = some_struct_create();
    
        9
  •  2
  •   Christoph    16 年前

    malloc() , memcpy()

    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    
    #define new(TYPE, ...) memdup(&(TYPE){ __VA_ARGS__ }, sizeof(TYPE))
    
    void * memdup(const void * obj, size_t size)
    {
        void * copy = malloc(size);
        return copy ? memcpy(copy, obj, size) : NULL;
    }
    
    struct point
    {
        int x;
        int y;
    };
    
    int main()
    {
        int * i = new(int, 1);
        struct point * p = new(struct point, 2, 3);
    
        printf("%i %i %i", *i, p->x, p->y);
    
        return 0;
    }
    
        10
  •  2
  •   Community user43968    5 年前

    下面是一个使用构造函数的简单程序。函数“default_constructor”在main内部被调用,没有任何显式函数调用。

    #include        <stdio.h> 
    
    void __attribute__ ((constructor)) default_constructor() 
    { 
        printf("%s\n", __FUNCTION__); 
    } 
    
    int main() 
    { 
        printf("%s\n",__FUNCTION__);
        return 0; 
    }
    

    输出: 默认构造函数

    在构造函数中,可以包含一些初始化语句,并使用析构函数释放内存,如下所示:,

    #include    <stdio.h> 
    #include    <stdlib.h>
    
    struct somestruct
    {
        int     empid;
        char *  name;
    };
    
    struct somestruct * str1;
    
    void __attribute__ ((constructor)) a_constructor() 
    { 
        str1 = (struct somestruct *) malloc (sizeof(struct somestruct));
        str1 -> empid = 30228;
        str1 -> name = "Nandan";
    } 
    
    void __attribute__ ((destructor)) a_destructor()
    {
        free(str1);
    }
    
    int main() 
    { 
        printf("ID = %d\nName = %s\n", str1 -> empid, str1 -> name);
        return 0;
    }
    

    希望这对你有帮助。

        11
  •  1
  •   paul    16 年前

    不是真的。如果我没记错的话,最接近类的是结构。分配内存并填充字段。我不知道你会怎么做一个通用的构造函数类型的东西。理论上,您可以编写一个宏来完成其中的一些操作。但不确定这是否真的值得。

        12
  •  1
  •   joeforker    16 年前

    如果这对你不起作用,那么看看GObject。 http://en.wikipedia.org/wiki/GObject . 它是GTK和Gnome中使用的C对象系统,几乎可以将“C中的对象”拖动到11。

    来自维基百科:

    GLib对象系统或GObject是一个自由软件库(由LGPL覆盖),它提供了一个可移植的对象系统和透明的跨语言互操作性。

    系统支持构造函数、析构函数、单继承、接口、虚拟公共和私有方法等。它也比在C++中做同样的事情要繁琐和困难。玩得高兴

        13
  •  0
  •   soulmerge    16 年前

    不,结构只是一堆数据。不能在结构中声明函数,因此无法为其创建构造函数。