有没有办法用C
编程语言编写类似于OO的代码?
也可以看看:
通过搜索“ [c] oo”找到。
Answers:
第一个C ++编译器(“带有类的C”)实际上会生成C代码,因此这绝对是可行的。
基本上,您的基类是一个struct;派生结构必须在第一个位置包括基本结构,以便指向“派生”结构的指针也将是指向基本结构的有效指针。
typedef struct {
data member_x;
} base;
typedef struct {
struct base;
data member_y;
} derived;
void function_on_base(struct base * a); // here I can pass both pointers to derived and to base
void function_on_derived(struct derived * b); // here I must pass a pointer to the derived class
函数可以作为函数指针作为结构的一部分,因此像p-> call(p)这样的语法成为可能,但是您仍然必须将指向结构的指针显式传递给函数本身。
struct derived*
给function_on_base
不会编译;即使地址正确,struct derived*
类型struct base*
也不同;但是,如果将指针从强制转换derived*
为base*
,它将起作用(但是您会错过编译时类型检查,而在运行时会崩溃)。@PatrickCollins重写是可能在C:pastebin.com/W5xEytbv
常见的方法是使用指向函数的指针定义结构。这定义了可以在任何类型上调用的“方法”。然后,子类型在此公共结构中设置自己的函数,然后将其返回。
例如,在Linux内核中,有struct:
struct inode_operations {
int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
struct dentry * (*lookup) (struct inode *,struct dentry *,
struct nameidata *);
...
};
每个注册的类型的文件系统的随后登记其自己的功能create
,lookup
和其余功能。其余代码则可以使用通用的inode_operations:
struct inode_operations *i_op;
i_op -> create(...);
C ++与C相距不远。
类是具有隐藏指针的结构,该指针指向称为VTable的函数指针表。Vtable本身是静态的。当类型指向具有相同结构的Vtable但指针指向其他实现时,您将得到多态性。
建议将调用逻辑封装在以struct作为参数的函数中,以避免代码混乱。
您还应该在函数(等效于C ++构造函数)和删除(C ++中的析构函数)中封装结构的实例化和初始化。无论如何,这些都是好的做法。
typedef struct
{
int (*SomeFunction)(TheClass* this, int i);
void (*OtherFunction)(TheClass* this, char* c);
} VTable;
typedef struct
{
VTable* pVTable;
int member;
} TheClass;
调用方法:
int CallSomeFunction(TheClass* this, int i)
{
(this->pVTable->SomeFunction)(this, i);
}
我查看了其他人的答案,并提出了以下建议:
#include <stdio.h>
typedef struct
{
int (*get)(void* this);
void (*set)(void* this, int i);
int member;
} TheClass;
int Get(void* this)
{
TheClass* This = (TheClass*)this;
return This->member;
}
void Set(void* this, int i)
{
TheClass* This = (TheClass*)this;
This->member = i;
}
void init(TheClass* this)
{
this->get = &Get;
this->set = &Set;
}
int main(int argc, char **argv)
{
TheClass name;
init(&name);
(name.set)(&name, 10);
printf("%d\n", (name.get)(&name));
return 0;
}
我希望能回答一些问题。
mylib_someClass_aMethod(this)
很可能。
VPRI的Ian Piumarta和Alessandro Warth撰写的文章Open Reusable Object Models的附录B是GNU C中一个对象模型的实现,大约140行代码。这是一本有趣的书!
这是使用C的GNU扩展(语句表达式)将消息发送到对象的宏的未缓存版本:
struct object;
typedef struct object *oop;
typedef oop *(*method_t)(oop receiver, ...);
//...
#define send(RCV, MSG, ARGS...) ({ \
oop r = (oop)(RCV); \
method_t method = _bind(r, (MSG)); \
method(r, ##ARGS); \
})
在同一个文档,有一个看看object
,vtable
,vtable_delegated
和symbol
结构,以及_bind
和vtable_lookup
功能。
干杯!
文件函数fopen,fclose,fread是C中OO代码的示例。它们代替了类中的私有数据,而是在FILE结构上工作,该FILE结构用于封装数据,并且C函数充当成员类函数。 http://www.amazon.com/File-Structures-Object-Oriented-Approach-C/dp/0201874016
#include <stdio.h>
typedef struct {
int x;
int z;
} base;
typedef struct {
base;
int y;
int x;
} derived;
void function_on_base( base * a) // here I can pass both pointers to derived and to base
{
printf("Class base [%d]\n",a->x);
printf("Class base [%d]\n",a->z);
}
void function_on_derived( derived * b) // here I must pass a pointer to the derived class
{
printf("Class derived [%d]\n",b->y);
printf("Class derived [%d]\n",b->x);
}
int main()
{
derived d;
base b;
printf("Teste de poliformismo\n");
b.x = 2;
d.y = 1;
b.z = 3;
d.x = 4;
function_on_base(&b);
function_on_base(&d);
function_on_derived(&b);
function_on_derived(&d);
return 0;
}
输出为:
Class base [3]
Class base [1]
Class base [4]
Class derived [2]
Class derived [3]
Class derived [1]
Class derived [4]
因此可以正常工作,它是一种多态代码。
UncleZeiv在一开始就对此进行了解释。
摘自Wikipedia:在编程语言和类型理论中,多态性(来自希腊语πολύς,polys,“很多”和μορφή,morphē,“形式,形状”)是对不同类型实体的单一接口。
所以我想说在C中实现它的唯一方法是使用可变参数以及一些(半)自动类型信息管理。例如,在C ++中,您可以编写(很琐碎):
void add( int& result, int a1, int a2 );
void add( float& result, float a1, float a2 );
void add( double& result, double a1, double a2 );
在C语言中,除其他解决方案外,您可以做的最好的事情是这样的:
int int_add( int a1, int a2 );
float float_add( float a1, fload a2 );
double double_add( double a1, double a2 );
void add( int typeinfo, void* result, ... );
然后,您需要:
我几乎可以肯定,多态性的任何其他实现都应该非常类似于这种实现。上面的答案似乎比多态性更着重于解决继承问题!
为了在C语言中也建立OO功能,您可以查看以前的答案。
但是,(如在其他重定向到该问题的其他问题中所提出的那样)是否要通过C语言示例理解多态性。也许我错了,但是我想不出任何像C指针算术那样容易理解的东西。在我看来,指针算法在C中固有地是多态的。在下面的示例中,根据输入结构的属性,相同的函数(OO中的方法),即加法(+),将产生不同的行为。
例:
double a*;
char str*;
a=(double*)malloc(2*sizeof(double));
str=(char*)malloc(2*sizeof(char));
a=a+2; // make the pointer a, point 2*8 bytes ahead.
str=str+2; // make the pointer str, point 2*1 bytes ahead.
免责声明:我是C语言的新手,非常期待得到纠正,可以从其他用户的评论中学习,或者完全删除此答案(如果有的话)。非常感谢,
我通常想做的是将结构包装在另一个包含有关包装类的元信息的结构中,然后构造作用在通用结构上的类似访问者的函数列表。这种方法的优点是您不需要修改现有结构,并且可以为结构的任何子集创建访问者。
采取通常的示例:
typedef struct {
char call[7] = "MIAO!\n";
} Cat;
typedef struct {
char call[6] = "BAU!\n";
} Dog;
我们可以将2个结构包裹在这个新结构中:
typedef struct {
const void * animal;
AnimalType type;
} Animal;
该类型可以是一个简单的int,但不要懒惰:
typedef enum {
ANIMAL_CAT = 0,
ANIMAL_DOG,
ANIMAL_COUNT
} AnimalType;
最好有一些包装功能:
Animal catAsAnimal(const Cat * c) {
return (Animal){(void *)c, ANIMAL_CAT};
}
Animal dogAsAnimal(const Dog * d) {
return (Animal){(void *)d, ANIMAL_DOG};
}
现在,我们可以定义“访问者”:
void catCall ( Animal a ) {
Cat * c = (Cat *)a.animal;
printf(c->call);
}
void dogCall ( Animal a ) {
Dog * d = (Dog *)a.animal;
printf(d->call);
}
void (*animalCalls[ANIMAL_COUNT])(Animal)={&catCall, &dogCall};
那么实际用法将是:
Cat cat;
Dog dog;
Animal animals[2];
animals[0] = catAsAnimal(&cat);
animals[1] = dogAsAnimal(&dog);
for (int i = 0; i < 2; i++) {
Animal a = animals[i];
animalCalls[a.type](a);
}
这种方法的缺点是,每次要将其用作泛型类型时,都必须包装结构。