C中的"阶级"行为

f.r*_*ues 4 c oop struct

说我有这个:

struct Person {
    char *name;
    char *occupation;
    int years_of_service;
    float salary;
};
Run Code Online (Sandbox Code Playgroud)

还有这个:

float calculate_salary(struct Person *who){
    float basesalary;

    char *doctor = "Doctor";
    char *janitor = "Janitor";

    int job1 = strcmp(who->occupation, doctor);
    int job2 = strcmp(who->occupation, janitor);

    if(job1 == 0){
        basesalary = 10000.0;
    }
    else if(job2 == 0){
        basesalary = 800.0;
    }

    return basesalary + basesalary*(who->years_of_service*0.1);
}
Run Code Online (Sandbox Code Playgroud)

计算人的工资的正确方法是什么?

在Python中我会在init中执行:

self.salary = self.calculate_salary()
Run Code Online (Sandbox Code Playgroud)

但由于C不是OO,我假设我必须首先创建没有薪水的人,然后设置薪水.像这样:

struct Person *joe = Person_create("Joe Alex", "Doctor",1);
joe->salary = calculate_salary(joe);
Run Code Online (Sandbox Code Playgroud)

但我希望有更好理解C的人告诉我这是否正确.

作为旁注,字符串同情是正确的吗?我发现这很奇怪,我应该使用开关吗?

hac*_*cks 9

计算人的工资的正确方法是什么?

你正在做的是使用plain struct作为对象并通过指针将其传递给函数.您已经在C中使用面向对象的方法.

如果你有兴趣实现你在python中展示的效果,那么calculate_salary在结构中添加一个指向函数的指针Person.

struct Person {
    char *name;
    char *occupation;
    int years_of_service;
    float salary;
    float (*fptr)(struct Person *); // fptr is a function pointer
};    
Run Code Online (Sandbox Code Playgroud)

这是一个驱动程序:

int main(void)
{
    struct Person *joe = malloc(sizeof(struct Person));
    joe->name = "Joe Alex";
    joe->occupation = "Doctor";
    joe->years_of_service = 1;

    joe->fptr = calculate_salary; //Function pointer Assignment
    (*joe).salary = (*joe).fptr(joe);
    printf("%f", joe->salary);
}  
Run Code Online (Sandbox Code Playgroud)

有一点需要注意,上面结构中使用的函数指针主要用于编写回调方法.

  • 我+ 1'但在这种情况下,使用`calloc`或创建自己的initPerson/createPerson函数以确保数据连贯一致更安全 (2认同)

Pav*_*rda 6

用C写一个简单的getter

面向对象语言中的基本目的是为相同类型的对象提供一组操作.通常,操作采用方法的形式.如果我们忽略了示例中显然不需要的高级概念,则方法只是对特定类型的对象进行操作的函数子例程.

这些方法可以像在任何其他函数中一样在C中实现,这正是您的实现calculate_salary().您可能希望将其重命名为遵循以下约定:C中的此类函数以类型名称为前缀,例如person_get_salary().

实施课程

您根本不需要salary结构中的字段,因为您将使用person_get_salary()函数(或方法)访问它.

struct person {
    char *name;
    char *occupation;
    int years_of_service;
};

float person_get_salary(struct person *person)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

然后简单地使用它.

float salary = person_get_salary(person);
Run Code Online (Sandbox Code Playgroud)

以上是方法调用的以下伪代码的C语法.

float salary = person.get_salary();
Run Code Online (Sandbox Code Playgroud)

或者基于以下属性的伪代码.属性看起来像语法中的字段,但是在后台使用gettersetter方法实现.

float salary = person.salary;
Run Code Online (Sandbox Code Playgroud)

仍然有两种主要方法可以使用这些结构,因为C 非常灵活,可以实现各种OOP位.

在堆栈上分配的对象

呼叫者可以为该人提供存储.优点是存储可以很好地在堆栈上.

struct person person;

person_init(&person, ...);

float salary = person_get_salary(&person);

...

person_cleanup(&person);
Run Code Online (Sandbox Code Playgroud)

在堆上分配的对象

该实现提供存储并在堆上分配对象.

struct person *person = person_new();

float salary = person_get_salary(person);

...

person_free(person);
Run Code Online (Sandbox Code Playgroud)

实施说明

您需要实现person_init()person_new()person_cleanup()person_free()相应.请注意,主要区别在于实现是否为对象分配和释放内存.在两种情况下,for name和的字符串occupation通常由实现分配和释放.

关于函数指针的注释

另一个答案是关于函数指针,它解决了问题的不同方面.

回答所示,简单方法可以实现为C函数,它接受指向对象的指针作为其第一个参数.函数指针对于高级功能(如通过虚方法的多态)非常有用.但即使这样,函数指针也存储在一个单独的结构中(通常称为虚方法表),该结构在相应类型的所有对象之间共享.

在某些情况下,您可能希望直接在对象中存储函数指针,但这些指针通常用于回调而不是简单的getter.

替代方法

另一种方法是实际使用薪水字段并在对象创建和/​​或修改时预先计算它.这样调用者只需从结构中读取工资字段,访问者函数(或方法)就没有必要了.