Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C中模拟OO风格的多态性?_C_Oop_Polymorphism - Fatal编程技术网

如何在C中模拟OO风格的多态性?

如何在C中模拟OO风格的多态性?,c,oop,polymorphism,C,Oop,Polymorphism,有没有办法用C编程语言编写类似OO的代码 另见: 通过在“[c]oo”上搜索找到。常见的方法是使用指向函数的指针定义struct。这定义了可以在任何类型上调用的“方法”。然后,子类型在这个公共结构中设置它们自己的函数,并返回它 例如,在linux内核中,有struct: struct inode_operations { int (*create) (struct inode *,struct dentry *,int, struct nameidata *); str

有没有办法用
C
编程语言编写类似OO的代码


另见:


通过在“[c]oo”上搜索找到。常见的方法是使用指向函数的指针定义struct。这定义了可以在任何类型上调用的“方法”。然后,子类型在这个公共结构中设置它们自己的函数,并返回它

例如,在linux内核中,有struct:

struct inode_operations {
    int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
    struct dentry * (*lookup) (struct inode *,struct dentry *, 
                               struct nameidata *);
    ...
};
然后,每种已注册类型的文件系统都为
创建
查找
和其余函数注册自己的函数。其余代码可以使用通用inode_操作:

struct inode_operations   *i_op;
i_op -> create(...);

第一个C++编译器(“C类”)实际上会生成C代码,所以这是可行的。 基本上,您的基类是一个结构;派生结构必须在第一个位置包含基结构,因此指向“派生”结构的指针也将是指向基结构的有效指针

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)这样的语法,但您仍然必须显式地将指向结构的指针传递给函数本身。

C++与C并不遥远

类是具有指向函数指针表(称为VTable)的隐藏指针的结构。Vtable本身是静态的。 当类型指向具有相同结构的Vtables,但指针指向其他实现时,就会得到多态性

建议将调用逻辑封装在以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);
}

文件函数fopen、fclose、fread是C中OO代码的示例。它们处理的不是类中的私有数据,而是用于封装数据的文件结构,C函数充当成员类函数。

由Ian Piumarta和Alessandro Warth撰写的文章附录B是GNU C中对象模型的实现,大约140行代码。这是一本引人入胜的书

下面是宏的未缓存版本,它使用C(语句表达式)的GNU扩展向对象发送消息:

在同一文档中,查看
对象
vtable
vtable\u委托
符号
结构,以及
\u绑定
vtable\u查找
功能


干杯

我看了其他人的答案,得出了以下结论:

#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;
}
#包括
类型定义结构
{
int(*get)(无效*此项);
无效(*集)(无效*本,int i);
国际会员;
}阶级;
int Get(void*this)
{
类*This=(类*)This;
返回此->成员;
}
void Set(void*this,int i)
{
类*This=(类*)This;
这个->成员=i;
}
void init(类*this)
{
此->获取=&get;
此->设置=&set;
}
int main(int argc,字符**argv)
{
类名;
init(&name);
(name.set)(&name,10);
printf(“%d\n”,(name.get)(&name));
返回0;
}
我希望这能回答一些问题

来自维基百科: 在编程语言和类型理论中,多态性(源自希腊语πολύς、poly、“多、多”和μορφή、morpē、form、shape)是为不同类型的实体提供单一接口

所以我想说,在C中实现它的唯一方法是使用可变参数和一些(半)自动类型信息管理。 例如,C++中可以编写(对不起琐碎):

在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, ... );
那么你需要:

  • 使用枚举/宏实现“typeinfo”
  • 用stdarg.h实现后一个函数
  • 告别C静态类型检查
  • 我几乎可以肯定,多态性的任何其他实现都应该与此非常相似。 相反,上面的答案似乎试图解决继承问题,而不是多态性问题

    #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;
    }
    
    所以它是有效的,它是一个多态代码


    Uncleziv在开始时解释了这一点。

    为了在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结构{
    char call[7]=“MIAO!\n”;
    }猫;
    类型定义结构{
    字符调用[6]=“BAU!\n”;
    }狗;
    
    我们可以在这个新结构中包装两个结构:

    typedef结构{
    const void*动物;
    动物型;
    }动物;
    
    该类型可以是一个简单的int,但我们不要懒惰:

    typedef枚举{
    动物猫=0,
    动物狗,
    动物数量
    }动物型;
    
    最好有一些包装功能:

    Animal catAsAnimal(常数Cat*c){
    返回(动物){(无效*)c,动物
    
    #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]
    
    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.