我是一名两年前学过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的这样一个优势可能非常有趣。我一直因为试图这样做而受到批评。我被给予的唯一原因是:"你没有垃圾收集器,所以不要"。有人可以给我一些专业人士,并解释为什么会出现这样一个非常糟糕的编程习惯"
答案 0 :(得分:1)
你可以在C中做OOP,但其中一个主要缺点是你必须传递这个指针。让我们假设您的结构中有一个指向printInfo()函数的指针,并且您希望打印该特定结构的信息。你必须这样做
my_struct-> printInfo(my_struct);
或者,如果my_struct不是指向结构的指针
my_struct.printInfo(安培; my_struct);
没有办法解决它。
对于你的第二个问题,我不确定在C中做OOP是否真的很实用。我是出于好奇而做到的,而且非常有趣。您可以获得继承,虚拟基类,多态和所有。如果您有兴趣,可以在这里查看:
答案 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 ++编译器仅仅是将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);
绝对否。正如您在前面的示例中所说,只要您需要多态性,指针必须是void *
并且您将丢失所有可能的类型检查。而且你也放弃了自动构造函数和析构函数的所有C ++好东西,自动这个指针等等。你用更多的代码结束,更难以阅读和调试。唯一可接受的用例(恕我直言)是:
请记住:如果发明了C ++,那一定是填补了C语言的空白。因此,不要尝试在C中创建C ++,除非您真的知道为什么要这样做。
这里再没有。 C ++没有垃圾收集,确实是一种OO语言。