easy struct继承&;伪多态与严格别名 如果有人回答我的问题,请不要告诉我使用C++。
所以,我正在用C语言制作一个小型库,它使用面向对象的方法。我选择使用C中两种主要继承方法中较不常见的一种:将基类型的成员复制到派生类型的开头。大概是这样的:easy struct继承&;伪多态与严格别名 如果有人回答我的问题,请不要告诉我使用C++。,c,pointers,inheritance,struct,strict-aliasing,C,Pointers,Inheritance,Struct,Strict Aliasing,所以,我正在用C语言制作一个小型库,它使用面向对象的方法。我选择使用C中两种主要继承方法中较不常见的一种:将基类型的成员复制到派生类型的开头。大概是这样的: struct base { int a; int b; char c; }; struct derived { int a; int b; char c; unsigned int d; void (*virtual_method)(int, char); }; 这种方法不如另一种(作为派生类型第一个成员
struct base {
int a;
int b;
char c;
};
struct derived {
int a;
int b;
char c;
unsigned int d;
void (*virtual_method)(int, char);
};
这种方法不如另一种(作为派生类型第一个成员的基类型的实例)流行,因为
memcpy
而不是直接解引用(如)。这看起来是个不错的解决方案。但是,函数调用会产生开销,是的,再次是冗长的。据我所知,memcpy
也可以通过将指向结构的指针强制转换为指向char
的指针,然后取消对它的引用来手动完成,(member\u type)(*((char*)(&struct\u pointer->member))=new\u值代码>嘎,又是冗长。这可以用宏来包装。但是,如果我们将指针强制转换为指向不兼容类型的指针,然后将其强制转换为char*
并取消对它的引用,那么这仍然有效吗?这样:(成员类型)(*((字符*)(&((结构不兼容的类型*)结构指针)->成员))=新的值代码>
volatile
的所有类型实例。我想知道为什么不经常出现这种情况<据我所知,code>volatile用于告诉编译器指针指向的内存可能会意外更改,从而基于指向的内存段不会更改的假设取消优化,这是所有严格别名问题的原因。当然,这仍然是未定义的行为;但是,对于某些类型的特定实例来说,这难道不是一个可行的跨平台解决方案吗我认为你关于通过
char*
进行角色转换的想法是无效的。
规则是:
对象的存储值只能由左值访问
具有以下类型之一的表达式
表达式的子表达式兼容,但整个表达式不兼容
我认为唯一现实的方法是组合:
struct base {
int a;
int b;
char c;
void (*virtual_method)(base*/*this*/,int, char);
};
struct derived {
struct base;
unsigned int d;
};
我意识到这是一种在智力上没有吸引力的继承方式
PS:我还没有将您的虚拟成员函数指针放在我的派生类中。它需要从base
访问,因此需要在那里声明(假设它是一个多态函数,同时存在于base
和derived
)。
我还添加了一个
这个
参数来丰富模型的触感 memcpy
应该是一条出路。
不要担心函数调用开销。通常情况下,没有memcpy
通常是编译器的固有特性,这意味着编译器应该为它内联最有效的代码,并且应该知道在哪里可以优化memcpies
不要将指针强制转换为不兼容的指针,然后取消引用。这是一条通向未定义行为的道路
如果您接受表达式语句和gcc的###uuu VA_uargs_uuu
,您可以拥有一个MC_base_方法(BaseType、BaseMethod、Derived_ptr等)
宏,该宏使用Derived_ptr
和…
调用BaseMethod
,只要您可以像使用原始结构的副本一样使用(例如,没有指向结构自身成员的指针)
下面是一个支持宏sugar的附加OOP示例:
//Helper macros for some C++-like OOP in plain C
#define MC_t_alias(Alias, ...) typedef __VA_ARGS__ Alias //like C++'s using
#define Struct(Nm,...) MC_t_alias(Nm, struct Nm); struct Nm __VA_ARGS__ //autypedefed structs
#define ro const //readonly -- I don't like the word const
//Helper macros for method declarations following my
//Type__method(Type* X, ...) naming convention
#define MC_mro(Tp,Meth, ...) Tp##__##Meth(Tp ro*X, ##__VA_ARGS__)
#include <stdio.h>
#include <string.h>
//I apend my data structs with _d to know they're data structs
Struct(base_d, {
int a;
int b;
char c;
});
Struct(derived_d, {
int a;
int b;
char c;
unsigned int d;
void (*virtual_method)(derived_d*, int, char);
});
//print method is unaware of derived_d
//it takes a `base_d const *X` (the mro (method, readonly) macros hides that argument (X==`this` in common OOP speak))
int MC_mro(base_d,print)
{
return printf("{ a=%d b=%d c=%d }", X->a, X->b, X->c);
}
/*
Call a (nonvirtual) base method
*/
#define MC_base_method(BaseType, Method, Derived_p, ...) \
({ \
int _r; /*if you conventionally return ints*/ \
/*otherwise you'll need __typeof__ to get the type*/ \
BaseType _b; \
memcpy(&_b, Derived_p, sizeof(_b)); \
_r = BaseType##__##Method(&_b, ##__VA_ARGS__); \
/*sync back -- for non-readonly methods */ \
/*a smart compiler might be able to get rid of this for ro method calls*/ \
memcpy(Derived_p, &_b, sizeof(_b)); \
_r; \
})
int main()
{
derived_d d = {1,2,3,4};
MC_base_method(base_d, print, &d);
}