说我有这个:
struct Person {
char *name;
char *occupation;
int years_of_service;
float salary;
};
和此:
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);
}
计算人的工资的正确方法是什么?
在Python中我会在init中执行它:
self.salary = self.calculate_salary()
但由于C不是OO,我假设我必须首先创建一个没有薪水的人,然后设置薪水。像这样:
struct Person *joe = Person_create("Joe Alex", "Doctor",1);
joe->salary = calculate_salary(joe);
但我希望有更好理解C的人告诉我这是否正确。
作为旁注,字符串同情是正确的吗?我发现这很奇怪,我应该使用开关吗?
答案 0 :(得分:9)
计算人的工资的正确方法是什么?
您正在做的是使用普通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
};
这是一个驱动程序:
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);
}
你应该注意的一点是,上面结构中使用的函数指针主要用于写callback methods。
答案 1 :(得分:6)
面向对象语言中类的基本目的是为相同类型的对象提供一组操作。大多数情况下,操作采用方法的形式。如果我们忽略了示例中显然不需要的高级概念,则方法只是对特定类型的对象进行操作的函数或子例程。
这些方法可以在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)
{
...
}
然后简单地使用它。
float salary = person_get_salary(person);
以上是方法调用的以下伪代码的C语法。
float salary = person.get_salary();
或者基于以下属性的伪代码。属性看起来像语法中的字段,但是在后台使用 getter 和 setter 方法实现。
float salary = person.salary;
使用这些结构仍有两种主要方法,因为C 非常灵活,可以实现各种OOP位。
来电者可以为此人提供存储空间。优点是存储可以很好地存储在堆栈中。
struct person person;
person_init(&person, ...);
float salary = person_get_salary(&person);
...
person_cleanup(&person);
实现提供存储并在堆上分配对象。
struct person *person = person_new();
float salary = person_get_salary(person);
...
person_free(person);
您需要相应地实施person_init()
或person_new()
以及person_cleanup()
或person_free()
。请注意,主要区别在于实现是否为对象分配和释放内存。在这两种情况下,name
和occupation
的字符串通常都会被实现分配和释放。
另一个答案是关于解决问题不同方面的函数指针。
如 this 回答所示,简单方法可以实现为C函数,它接受指向对象的指针作为其第一个参数。函数指针对于高级功能(如通过虚方法的多态)非常有用。但即使这样,函数指针也存储在一个单独的结构中(通常称为虚方法表),该结构在相应类型的所有对象之间共享。
有些情况下,您可能希望直接在对象中存储函数指针,但这些指针通常用于回调而不是简单的getter。
另一种方法是实际使用 salary 字段并在对象创建和/或修改时预先计算它。这样调用者只会从结构中读取 salary 字段,并且访问者函数(或方法)也不是必需的。