【问题标题】:Class approximation in C - Is this witchcraft or technically acceptable?C 中的类逼近 - 这是巫术还是技术上可以接受?
【发布时间】:2022-01-15 15:37:57
【问题描述】:

我只需要用 C 和 C 语言做一个大型项目,不需要外部库(SDL 除外)。 我开始寻找在 C 中做某种类的方法,是什么导致了我:

typedef void (*voidFunction)(void);

typedef struct{
    int id;                             
    voidFunction printId;
} Object;

Object *new_Object(int id){
    Object *newObject = malloc(sizeof(Object));
    newObject->id = id;
    void printId(){
        static Object *this = NULL;
        if(!this) this = newObject;
        printf("%d\n", this->id);
    };
    newObject->printId = printId;
    return newObject;
}

int main(){
    Object *object = new_Object(5);
    object->printId();
    object->id++;
    object->printId();
    return 0;
}

主输出:

5
6

所以这行得通,但它似乎合理吗? 如果我将这种架构用于大型项目,我是否应该期待反弹?也许我在不知不觉中输入了分配的内存?

【问题讨论】:

  • 这对您有什么好处?类提供了很多特性,而这一切让你获得的只是方法调用的一种非常有限的方式。在 C 中重新发明类是丑陋的,而且写/读起来有点糟糕,所以首先要问的问题是:“我的伪类让我得到什么?值得丑陋吗?”
  • 好吧,例如,我将有大量类似对象的属性,但显示方式却截然不同。这将使我能够对链表中的每个对象调用 object->render()。因为我的课程很少,但会经常使用和调用它们,所以我可以为我得到的抽象留一点丑陋。我的问题真的是:这是未来的段错误材料吗?
  • new_Object 中定义一个嵌套函数只能通过编译器提供的扩展来实现。这不是标准的 C。

标签: c class


【解决方案1】:

在 C 中实现多态的技术由来已久,请查看此答案,例如 https://stackoverflow.com/a/351745/4433969

您的实现似乎被破坏了。嵌套函数是非标准扩展。我对静态这个变量也有疑问。

【讨论】:

    【解决方案2】:

    非标准嵌套函数printId使用不正确。在 GCC 文档Nested functions 中可以阅读:

    如果你试图在包含函数退出后通过它的地址调用嵌套函数,那么一切都会崩溃。

    嵌套函数通过蹦床调用,蹦床是位于堆栈上的一小段可执行代码。此代码在父函数退出时失效。

    虽然函数不引用任何局部变量,但代码可能会起作用。编译器可能会避免蹦床,而是创建一种“匿名”静态函数。

    惯用的解决方案应该将指向“Object”的指针作为参数,而不是使用静态变量。

    typedef struct Object {
        int id;                             
        void (*printId)(struct Object*);
    } Object;
    
    void printId(Object *this){
            printf("%d\n", this->id);
    };
    
    ...
    
    object->printId(object);
    

    【讨论】:

      【解决方案3】:

      使用struct 来组织数据以进行批量处理具有优势。但是,使用函数指针而不是直接调用函数的唯一优点是:

      1. 允许函数指针针对对象的不同实例指向具有相同类型的不同函数。
      2. 对链接器隐藏“成员”函数定义。例如,函数printId 可以在包含“构造函数”new_Object 定义的模块中声明为static

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-08-26
        • 1970-01-01
        • 2017-08-31
        • 1970-01-01
        • 2012-01-25
        • 2016-12-05
        • 2010-10-12
        • 1970-01-01
        相关资源
        最近更新 更多