如何在C语言中使用父类数组存储子类对象?
- 行业动态
- 2025-01-24
- 5
在Java编程中,父类数组可以存储子类对象,这是多态性的一种体现。通过这种方式,可以方便地对不同类型的 子类对象进行统一管理和操作,增强了代码的可维护性和扩展性。
在 C 语言中,父类数组存储子类对象是一种常见的面向对象编程技巧,下面将详细解释如何在 C 语言中实现这一功能:
1、定义基类和派生类
首先需要定义一个基类(父类)和一个或多个派生类(子类),基类通常包含一些通用的属性和方法,而派生类则继承自基类,并可以添加自己的特定属性和方法。
typedef struct { int id; char name[20]; } BaseClass; typedef struct { BaseClass base; // 继承基类的属性 double score; // 子类特有的属性 } DerivedClass;
这里BaseClass 是基类,包含id 和name 两个成员变量;DerivedClass 是派生类,它继承了BaseClass 的所有属性,并新增了score 属性。
2、创建子类对象并存储到父类数组中
可以创建一个指向基类的指针数组,用于存储子类对象的地址,由于子类对象兼容基类指针,所以可以将子类对象的地址赋值给基类指针数组的元素。
int main() { BaseClass *array[2]; // 创建一个指向基类的指针数组,大小为 2 // 动态分配内存并初始化子类对象 DerivedClass *obj1 = (DerivedClass *)malloc(sizeof(DerivedClass)); obj1->base.id = 1; strcpy(obj1->base.name, "Tom"); obj1->score = 95.5; DerivedClass *obj2 = (DerivedClass *)malloc(sizeof(DerivedClass)); obj2->base.id = 2; strcpy(obj2->base.name, "Jerry"); obj2->score = 88.0; // 将子类对象存储到基类指针数组中 array[0] = (BaseClass *)obj1; array[1] = (BaseClass *)obj2; // 现在可以通过基类指针访问子类对象的成员 for (int i = 0; i < 2; i++) { printf("ID: %d, Name: %s ", array[i]->id, array[i]->name); if (i == 0) { // 假设我们知道第一个元素是 DerivedClass 类型 printf("Score: %.1f ", ((DerivedClass *)array[i])->score); } } // 释放动态分配的内存 free(obj1); free(obj2); return 0; }
在这个例子中,首先创建了一个大小为 2 的指向基类的指针数组array,然后动态分配了两个DerivedClass 类型的对象obj1 和obj2,并分别初始化它们的成员变量,接着将这两个子类对象的地址赋值给基类指针数组array 的元素,通过基类指针遍历数组,并尝试访问子类对象的成员,需要注意的是,在访问子类特有的成员时,需要进行显式的类型转换。
3、多态性在父类数组中的应用
如果基类和派生类中都有相同名称的成员函数,并且这些函数的参数列表和返回类型也相同,那么可以通过基类指针调用这些成员函数,实现多态性。
typedef struct { int id; char name[20]; void (*display)(struct BaseClass *); // 函数指针,用于实现多态性 } BaseClass; typedef struct { BaseClass base; double score; void (*display)(struct DerivedClass *); // 子类特有的 display 函数 } DerivedClass; void baseDisplay(BaseClass *b) { printf("BaseClass ID: %d, Name: %s ", b->id, b->name); } void derivedDisplay(DerivedClass *d) { printf("DerivedClass ID: %d, Name: %s, Score: %.1f ", d->base.id, d->base.name, d->score); } int main() { BaseClass *array[2]; DerivedClass *obj1 = (DerivedClass *)malloc(sizeof(DerivedClass)); obj1->base.id = 1; strcpy(obj1->base.name, "Alice"); obj1->score = 92.0; obj1->base.display = (void (*)(BaseClass *))derivedDisplay; // 将子类的 display 函数赋值给基类的函数指针 DerivedClass *obj2 = (DerivedClass *)malloc(sizeof(DerivedClass)); obj2->base.id = 2; strcpy(obj2->base.name, "Bob"); obj2->score = 85.0; obj2->base.display = (void (*)(BaseClass *))derivedDisplay; array[0] = (BaseClass *)obj1; array[1] = (BaseClass *)obj2; for (int i = 0; i < 2; i++) { array[i]->display(array[i]); // 通过函数指针调用 display 函数,实现多态性 } free(obj1); free(obj2); return 0; }
在这个例子中,BaseClass 和DerivedClass 都有一个display 成员函数,但它们的实现不同,通过将子类的display 函数赋值给基类的函数指针,可以在运行时根据对象的实际类型调用相应的display 函数,从而实现多态性,在主函数中,通过基类指针数组遍历对象,并调用display 函数来显示对象的信息。
FAQs:
Q: 为什么需要将子类对象转换为父类类型才能存储到父类数组中?
A: 因为数组的元素类型必须是一致的,而子类对象是父类的派生类型,它们之间存在继承关系,将子类对象转换为父类类型后,就可以将它们统一存储到父类数组中,同时仍然可以通过基类指针访问子类对象的公共部分。
Q: 如何在不知道具体子类类型的情况下,通过父类指针访问子类对象的成员?
A: 一种方法是使用 C 语言的union 或struct 嵌套来实现,另一种方法是使用函数指针和多态性,通过在基类中定义函数指针,并在子类中实现相应的函数,然后在运行时根据对象的实际类型调用正确的函数,还可以使用void 指针和类型转换来强制转换指针类型,但这需要确保转换是正确的,否则可能会导致未定义的行为。
本站发布或转载的文章及图片均来自网络,其原创性以及文中表达的观点和判断不代表本站,有问题联系侵删!
本文链接:http://www.xixizhuji.com/fuzhu/400796.html