C中的默认构造函数

对于使用结构定义的C用户类型,是否有某种方法可以使用某种默认构造函数(如C ++版本)?

我已经有一个像快速初始化程序一样工作的宏(就像pthread_mutex ),但我想知道你是否可以在声明中填充结构的某些(或所有)字段。

例如,使用pthread_mutex示例,我想

 pthread_mutex_t my_mutex; 

具有相同的效果

 pthread_mutex_t my_mutex = PTHREAD_MUTEX_INITIALIZER; 

您可以创建带有指向结构的指针的初始化函数。 这是常见的做法。

也是创建结构并初始化它的函数(如工厂) – 因此在“客户端”代码中从未有过“未初始化”结构的时间。 当然 – 假设人们遵循惯例并使用“构造函数”/工厂……

可怕的伪代码,没有错误检查malloc或免费

 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中完成所有这些工作。

在这种情况下,C ++与C不同,它没有“类”。 但是,C(与许多其他语言一样)仍然可以用于面向对象的编程。 在这种情况下,构造函数可以是初始化结构的函数。 这与构造函数相同(只有不同​​的语法)。 另一个区别是你必须使用malloc()(或某些变体)分配对象。 在C ++中,您可以使用’new’运算符。

例如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; } 

函数’init_A_types’在C ++中作为构造函数运行。

让我们来谈谈在过去被认为是最佳实践的完整工程解决方案。

结构的问题是一切都是公共的,所以没有数据隐藏。

我们可以解决这个问题

您创建两个头文件。 一个是代码客户端使用的“公共”头文件。 它包含这样的定义:

 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)); } 

会发生什么是您在公共头文件中为结构做出前向声明。 现在你的结构是不透明的,这意味着客户不能与它们混在一起。 然后,在完整声明中,在每个结构的开头都包含一个析构函数,您可以调用它。 您可以为每个人使用相同的malloc分配器具有相同的disposefunction。 您为要公开的元素创建公共set / get函数。

突然间,你的代码更加清晰。 您只能从分配器或调用分配器的函数获取结构,这意味着您可以瓶颈初始化。 您构建析构函数以便可以销毁对象。 你去吧。 顺便说一下,比t_DisposableStruct更好的名字可能是t_vTableStruct,因为它就是这样。 您现在可以通过使用vTableStruct来构建虚拟inheritance,该vTableStruct是所有函数指针。 你也可以用纯粹的oo语言(通常)做一些你不能做的事情,比如在运行中更改vtable的select元素。

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

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

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

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

如果你想知道你是否可以在C中拥有“普通”成员函数。嗯,你可以在某种程度上。 我更喜欢object-as-first-argument风格。 您将指向结构的指针作为第一个参数传递。 这样,您可以使用多个函数来定义对象的接口:

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

如果你用那种风格写作,你最后得到的是一种抽象的数据类型。 我已经看到人们通过将函数指针放入其结构中然后执行以下操作来模拟C ++中使用的成员函数调用语法:

 obj.get_integer(&obj); 

它被linux内核用于定义文件系统驱动程序的接口。 这是一种人们喜欢或可能不喜欢的写作风格。 我不太喜欢它,因为我继续使用结构的成员来获取数据,而不是模仿成员函数调用看起来像流行的面向对象语言。

基本上,C ++创建包含方法地址的指针列表。 此列表称为类定义(类def中有更多数据,但我们现在忽略它)。

在纯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_definition的类定义创建“某事”的新实例。 METHOD将在此实例上调用“方法”。 请注意,对于实际代码,您需要检查inst实际上是某个实例(比较类指针,类似于此)。

inheritance有点棘手,留给读者练习。

请注意,您可以使用纯C在C ++中执行所有操作.C ++编译器不会用其他东西神奇地替换您的CPU。 它需要更多的代码才能完成。

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

假设您想在C中执行此操作,那么您的问题不是关于C ++中的结构:

我通常做的是我只创建一个函数init_whatever,它接受一个指向struct(或其他变量)的指针,并将其设置为我想要的值。

如果它是一个全局变量(初始化为零),您可以通过在其中包含“初始化”标志来模拟无参数构造函数,然后让其他函数检查该标志,并初始化该结构如果该标志是零。 不过,我不确定这是个好主意。

并且,正如其他人所说,你也可以用宏做一些可怕的事……

已经提到使用函数来创建和处理结构。 但是在评论中你提到你想要一个“默认构造函数” – 我认为你的意思是你想将一些(所有?)的struct字段初始化为默认值。

这是使用一些编码约定在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(); 

这是malloc()memcpy()和C99复合文字的一点宏观魔法:

 #include  #include  #include  #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; } 

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

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

输出:default_constructor main

在构造函数中,你可以在构造函数中包含一些初始化语句,最后可以在析构函数中释放为fallow,

 #include  #include  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; } 

希望这会帮助你。

并不是的。 如果我没记错的话,你最接近课程的是结构。 您分配内存并填充字段。 我不知道你将如何为此创建一个通用的构造函数类型的东西。 从理论上讲,你可以编写一个可以做到这一点的宏。 不确定这是否真的值得。

您可能想看一下C ++编译器。 它为您提供了更多面向对象的function,而不是您能够以更优雅和标准的方式使用具有类似C语法的语言,而不是尝试使用库和宏将构造函数等用于C语言。

如果这不适合你,那么看看GObject。 http://en.wikipedia.org/wiki/GObject 。 它是GTK和Gnome中使用的C的对象系统,它几乎将“C中的对象”曲解为11。

来自维基百科:

GLIB对象系统或GObject是一个免费软件库(由LGPL提供),它提供了一个便携式对象系统和透明的跨语言互操作性。

系统支持构造函数,析构函数,单inheritance,接口,虚拟公共和私有方法等。 与在C ++中执行相同的操作相比,这也更加繁琐和困难。 玩得开心!

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