说我有这个:
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的人告诉我这是否正确.
作为旁注,字符串同情是正确的吗?我发现这很奇怪,我应该使用开关吗?
计算人的工资的正确方法是什么?
你正在做的是使用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)
有一点需要注意,上面结构中使用的函数指针主要用于编写回调方法.
面向对象语言中类的基本目的是为相同类型的对象提供一组操作.通常,操作采用方法的形式.如果我们忽略了示例中显然不需要的高级概念,则方法只是对特定类型的对象进行操作的函数或子例程.
这些方法可以像在任何其他函数中一样在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)
或者基于以下属性的伪代码.属性看起来像语法中的字段,但是在后台使用getter和setter方法实现.
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.
另一种方法是实际使用薪水字段并在对象创建和/或修改时预先计算它.这样调用者只需从结构中读取工资字段,访问者函数(或方法)就没有必要了.