我有一个关于具有“变量成员列表”的结构的问题,类似于“变量参数列表”,我们可以将函数定义为具有。 就C语言基础而言,我可能听起来很愚蠢或完全不合适,但如果我错了,请纠正我。
那么我可以有这样的C结构:
struct Var_Members_Interface
{
int intMember;
char *charMember;
... // is this possible?
};
我的想法是拥有一个可以由类实现的c样式接口,但这些类在此结构中可以有其他成员。但是,它们必须具有intMember和charMember。
提前致谢。
答案 0 :(得分:2)
C99中最接近的近似值(但不是C89)是在结构末端有一个灵活的阵列成员:
struct Var_Members_Interface
{
int intMember;
char *charMember;
Type flexArrayMember[];
};
现在,您可以在结尾处使用类型为Type
的数组动态分配结构,并访问该数组:
struct Var_Members_Interface *vmi = malloc(sizeof(*vmi) + N * sizeof(Type));
vmi->flexArrayMember[i] = ...;
请注意,这不能在C ++中使用。
但这与你所追求的并不是非常接近。你所追求的是不能用单一结构类型在C中完成,并且只能通过继承在C ++中近似 - 参见其他答案。
你可以逃脱的一个技巧 - 通常 - 在C中使用多种结构类型和大量的强制转换:
struct VM_Base
{
int intMember;
char *charMember;
};
struct VM_Variant1
{
int intMember;
char *charMember;
int intArray[3];
};
struct VM_Variant2
{
int intMember;
char *charMember;
Type typeMember;
};
struct VM_Variant3
{
int intMember;
char *charMember;
double doubleMember;
};
现在,通过一些大锤演员,您可以编写带有“struct VM_Base *
”参数的函数,并传入指向任何VM_VariantN
类型的指针。 'intMember
'可能用于说明您实际拥有哪些变体。这或多或少与POSIX套接字函数有关。存在不同类型的套接字地址,并且结构具有不同的长度,但是它们具有共同的前缀,并且最终被调用正确的代码,因为公共前缀标识套接字地址的类型。 (设计并不优雅;但它是标准的 - BSD套接字的事实标准 - 在POSIX标准化之前。而BSD设计在C89之前,更不用说C99了。现在是从头开始设计,没有要求为了与现有代码兼容,可以采用不同的方式。)
这种技术像罪一样丑陋,需要强大的演员才能使它编译 - 并且非常注意使其正常工作。你不应该为C ++中的这种混乱而烦恼。
答案 1 :(得分:1)
在C语言中使用直接语言支持不能做这样的事情;但是在C ++中,扩展结构的类将继承这些数据成员并可以添加自己的数据。所以在C ++中,不仅可以你这样做,而且这是一种正常的操作模式。
答案 2 :(得分:1)
首先,您需要了解struct
到底是什么。
C中的结构只是用于解释内存中的标准。
要了解这意味着什么,让我们使用你的结构:
struct Var_Members_Interface
{
int intMember;
char *charMember;
};
struct Var_Members_Interface instance; //An instance of the struct
这意味着,“我将保留一些内存并将其称为instance
,我会将前几个字节解释为一个整数,而接下来的几个字节意味着指向某个地方在记忆中。“
鉴于此,拥有“变量成员”结构是没有意义的,因为结构只是现有内存块的布局规范 - 和现有的块没有“可变”的长度。
答案 3 :(得分:1)
你可以像旧的X11 Xt widget library那样做:
struct Var_Members_Interface {
int intMember;
char *charMember;
};
struct Other_Part {
int extraInt;
char *extraString;
}
struct Var_Other_Interface {
struct Var_Members_Interface base;
struct Other_Part other;
};
只要您对分配,对齐和填充问题小心,那么这将有效:
struct Var_Other_Interface *other = create_other();
struct Var_Members_Interface *member = (struct Var_Other_Interface *)other;
struct Var_Other_Interface *back_again = (struct Var_Other_Interface)member;
您可以根据需要深入嵌套结构以获得单个继承层次结构。
这种事情不适合佯攻:你必须非常小心你的分配,结构嵌套等。
看看旧学校的Xt小部件,你会明白的; Xt小部件通常在三个文件中实现:C源文件,带有功能接口的公共头,以及用于定义结构布局的私有头(子类化需要这个)。
例如,我以前在mgv中使用的Ghostscript小部件如下所示:
typedef struct {
/* Bunch of stuff. */
} GhostviewPart;
typedef struct _GhostviewRec {
CorePart core;
GhostviewPart ghostview;
} GhostviewRec;
CorePart
是标准的Xt小部件定义,GhostviewRec
是实际的小部件本身。
答案 4 :(得分:0)
不完全是您要查找的内容,但您可以在结构中创建一个void指针,该指针可用于指向定义新类型的另一个结构。
struct Var_Members_Interface
{
int intMember;
char *charMember;
void *otherMembers;
};
修改:此article中的解决方案可能更接近您所寻找的内容。
答案 5 :(得分:0)
我认为你有两个选择。你可以模仿C ++的功能但不幸的是,你必须看到所有的血腥细节。您可以定义公共基础结构,并将其作为所有变体结构的成员,例如
struct VM_Base
{
int intMember;
char *charMember;
};
struct VM_Variant1
{
struct VM_Base base;
int foo;
};
struct VM_Variant2
{
struct VM_Base base;
char *charMember;
double bar;
};
struct VM_Variant3
{
struct VM_Base base;
char *charMember;
char baz[10];
};
指向任何变体结构的指针也是指向变体结构的基本成员的指针,因此您可以自由地转换为基本成员。回到另一个方向显然更成问题,因为你需要检查以确保你投射到正确的类型。
你可以使用union来取消强制转换,例如
struct VM_Variant1
{
struct VM_Base base;
int foo;
};
struct VM_Variant2
{
struct VM_Base base;
char *charMember;
double bar;
};
struct VM_Variant3
{
struct VM_Base base;
char *charMember;
char baz[10];
};
struct VM
{
int intMember;
char *charMember;
union
{
struct VM_Variant1 vm1;
struct VM_Variant2 vm2;
struct VM_Variant3 vm3;
}
};
第二种方法不需要类型转换。您可以像这样访问成员:
double aDouble = aVMStruct.vm2.bar;
联合的三个成员在内存中相互叠加,因此分配的块只是三个变体中最大的一个的大小。