面向对象的C - 变量在struct + pro和cons中

时间:2016-02-15 10:35:55

标签: c oop data-structures modularity

我是一名两年前学过C的年轻学生。我刚刚发现了更复杂的东西,比如面向对象的C。

我的第一个问题是:

1)您如何访问变量?目标是根据已实例化的结构为这些变量设置特定值。 所以我喜欢这样的事情:

myStruct* myStrPtr;
myStruct2* myStrPtr;

myStrPtr = initializeStruct();
myStrPtr->printContent //prints for example 55

myStrPtr2 = initializeStruct();
myStrPtr2->printContent //prints for example 6548

示例

typedef struct {

    void (*sum)(int a, int b);
    void (*printContent)(void);

    int content;

}myStruct;

void printInhoud(void){
   printf("content: %d\n", content);}

void sum(int a, int b){

 /***********THIS DOESN T WORK OBVIOUSLY************/
    this->content = a+b;
    printf("calculated sum: %d", sum);
  }


myStruct * initializeStruct(void)
{
    myStruct* myStrPtr = malloc(sizeof(myStruct));
    myStrPtr -> foo = foo ; 
    mynStrPtr->printContent = printContent;

    return myStrPtr;
}

 void freeMem(myStruct * myStructPtr)
{
   free(myStructPtr);
}


int main (void)
{
    int a= 1;
    int b=33;

    myStruct* myStrPtr;

    myStrPtr = initializeStruct();

    myStrPtr->printContent();

    return 0;
}

2)我的第二个问题是:以这种方式进行编程的专业人士和专业人士是什么?我认为如果我能够在结构中添加变量并像在OOP中那样访问它们,我会获得一个很大的优势:模块化。我积极参与嵌入式软件,并相信在嵌入式系统上拥有OOP的这样一个优势可能非常有趣。我一直因为试图这样做而受到批评。我被给予的唯一原因是:"你没有垃圾收集器,所以不要"。有人可以给我一些专业人士,并解释为什么会出现这样一个非常糟糕的编程习惯"

3 个答案:

答案 0 :(得分:1)

你可以在C中做OOP,但其中一个主要缺点是你必须传递这个指针。让我们假设您的结构中有一个指向printInfo()函数的指针,并且您希望打印该特定结构的信息。你必须这样做

my_struct-> printInfo(my_struct);

或者,如果my_struct不是指向结构的指针

my_struct.printInfo(安培; my_struct);

没有办法解决它。

对于你的第二个问题,我不确定在C中做OOP是否真的很实用。我是出于好奇而做到的,而且非常有趣。您可以获得继承,虚拟基类,多态和所有。如果您有兴趣,可以在这里查看:

https://github.com/vladcc/object-oriented-c

答案 1 :(得分:0)

不仅封装,许多其他OOP概念可以用很少的努力用C实现。

这是一个例子。

//
// cobj.h
//

#ifndef __COBJ_H__
#define __COBJ_H__
struct _cobj_priv;
typedef struct _cobj {
    struct _cobj_priv *priv;

    void (*set_data)(struct _cobj *obj, int data);
    int (*get_data)(struct _cobj *obj);
    void (*print_data)(struct _cobj *obj);
} cobj_t;

cobj_t *new_struct(void);
void free_struct(cobj_t *obj);

#endif /* __COBJ_H__ */

//
// cobj.c
//

#include "cobj.h"
#include <stdio.h>
#include <stdlib.h>

//
// Internal section
//
struct _cobj_priv {
    int data;
};

static void set_data (struct _cobj *obj, int data) {
    struct _cobj_priv *this = (obj && obj->priv) ? obj->priv: NULL;

    if (this) {
        this->data = data;
    }
}

static int get_data (struct _cobj *obj) {
    struct _cobj_priv *this = (obj && obj->priv) ? obj->priv: NULL;

    return (this)? this->data : 0;
}

static void print_data (struct _cobj *obj) {
    struct _cobj_priv *this = (obj && obj->priv) ? obj->priv: NULL;

    if (this)
        printf("%d\n", this->data);
}

//
// APIs section
//
cobj_t *new_struct(void) {
    cobj_t *obj = malloc(sizeof(cobj_t));

    if (obj) {
        obj->priv = malloc(sizeof(struct _cobj_priv));

        if (obj->priv) {
            obj->priv->data = 0;
        }

        obj->set_data = &set_data;
        obj->get_data = &get_data;
        obj->print_data = &print_data;
    }

    return obj;
}

void free_struct(cobj_t *obj) {
    if (obj) {
        if (obj->priv)
            free(obj->priv);

        free(obj);

        obj = null;
    }
}

//
// main.c
//

#include "cobj.h"
#include <stdio.h>

int main(int argc, char *argv[]) {
    cobj_t *obj = new_struct();

    if (obj) {
        obj->print_data(obj);
        obj->set_data(obj, 100);
        obj->print_data(obj);

        printf("> get data return %d\n", obj->get_data(obj));
    }

    return 0;
}

结果:

0
100
> get data return 100

在C中,struct的方法是函数指针,它们不知道struct的存在,因此它们无法访问struct成员。您需要将struct实例作为参数传递给方法,以便访问其成员。

答案 2 :(得分:0)

免责声明:我不确定以下是否真的是一个答案,但是评论的时间太长了。

是否可以在C中进行OOP?

是的。第一个C ++编译器仅仅是将C ++源代码转换为C的预处理器。当然,你既没有构造函数也没有析构函数,所以你必须明确地调用它们,你必须使用组合模式进行继承,你必须有虚拟方法的vtable并且必须明确地通过this指针。

ctor,dtor,动态数组和方法的简单示例:

struct __foo {
    int *arr;
    int n;
};
typedef struct __foo foo;
bool init_foo(foo *f, int n) {
    f->arr = malloc(n * sizeof(int));
    f->n = n;
    return (f->arr != NULL);
}
void clean_foo(foo *f) { free(f->arr); }
bool set(int index, int value, foo *f) {  // same for get...
    if ((index >= f->n) || (index < 0)) return false;
    f->arr[index] = value;
    return true;
}

用法:

foo f;
init_foo(8, &f);
set(5, 2, &f);
clean_foo(&f);

继承和虚方法的更复杂的例子:

typedef struct {
    int age;
    const char *name;
    const char* (*say)(void *);
} animal;
typedef struct {
    animal parent;
} dog;
typedef struct {
    animal parent;
} cat;
void init_animal(int age, const char *name, animal *a) {
    a->age = age;
    a->name = name;
}
char *pre_say(animal *this) {
    char * msg = malloc(strlen(this->name) + 11);
    strcpy(msg, this->name);
    strcat(msg, " says ");
    return msg;

const char * wow(void *an) {
    animal *this = (animal *) an;
    char * msg = pre_say(this);
    strcat(msg, "Woof");
    return msg;
}
const char* meeow(void *an) {
    animal *this = (animal *) an;
    char * msg = pre_say(this);
    strcat(msg, "Meew");
    return msg;
}
void init_dog(int age, const char * name, dog *d) {
    init_animal(age, name, &(d->parent));
    d->say = &woof;
}
void init_cat(int age, const char * name, cat *c) {
    init_animal(age, name, &(c->parent));
    d->say = &meeow;
}

用法示例:

dog d;
init_dog(2, "Rintintin", &d);
cat c;
init_cat(3, "Tom", &c);
const char *msg = (d.say)(&d);  // msg <- Rintintin says Woof
free(msg);
msg = (c.say)(&c);    // msg <- Tom says Meew
free(msg);

我们应该在C中做OOP吗?

绝对。正如您在前面的示例中所说,只要您需要多态性,指针必须是void *并且您将丢失所有可能的类型检查。而且你也放弃了自动构造函数和析构函数的所有C ++好东西,自动这个指针等等。你用更多的代码结束,更难以阅读和调试。唯一可接受的用例(恕我直言)是:

  • 连接C ++和C
  • 对于只有C编译器的平台,C ++代码的最小转换。
  • 低级代码(内核或高性能库),您不希望对C ++的开销感到厌倦,但仍然需要OOP。

请记住:如果发明了C ++,那一定是填补了C语言的空白。因此,不要尝试在C中创建C ++,除非您真的知道为什么要这样做。

垃圾收集器与OOP有关吗?

这里再没有。 C ++没有垃圾收集,确实是一种OO语言。