c语言中面向对象的作用,在C语言中实现面向对象

C语言是结构化和模块化的语言,它是面向过程的。但它也可以模拟C++实现面向对象的功能。那么什么是对象呢?对象就是一个包含数据以及于这些数据有关的操作的集合,也就是包含数据成员和操作代码(即成员函数)。用C语言实现面向对象功能主要就是实现拟“类”的继承,函数的重载等操作,这些主要是通过结构体和指针函数实现的。

在C++和Java中,多态行为是由一种动态连接机实现的,比如,在C++中定义如下的类 Base 和它的子类 Sub:

class Base {

int data;

public:

Base() : data(3) {}

virtual int getData() const {

return data;

}

};

class Sub:public Base {

int data;

public:

Sub() : data(5) {}

int getData() const {

return data;

}

};

那么如果有一个Base 类型的指针指向了一个Sub类,通过这个指针调用getData()时将返回子类Sub中的data:初始值5。这样,如果有一个储存基类型指针的数组, 但这些指针有的指向基类,有的指向子类,那么我就可以通过指针统一地调用 getData() 函数,依然能够得到正确的值。

怎么在C中也实现类似的功能呢?

要想根据基类的指针正确地选择应该调用的函数,一个合适的备选方案是用函数指针,即在基类的结构中定义一个函数指针,这个函数指针的值将根据具体对象的类别设置,比如上面的C++代码可以用C写成这样:

struct Base {

int data;

int (*getData)( struct Base * );

};

struct Sub {

struct Base base;

int data;

};

这样,如果有一个struct Base 型的指针 base,通过 base->getData(base) 就可以得到正确的值,这样就实现了我们刚才的目的。但是如果有一个真正的 struct Sub 型的指针 sub,要想通过 sub 来调用正确的 getData,则至少要经过两次强制类型转换(如果不想让编译器发出警告的话)。这在写代码时是比较麻烦的。我们可以在sub中也添加一个函数指针,它 指向专门为 struct Sub 写的函数,这样就可以解决这种不便之处:

struct Base {

int data;

int (*getData)( struct Base * );

};

struct Sub {

struct Base base;

int (*getData)( struct Sub * );

int data;

};

这样一来,我们需要适当地初始化这些指针,让它们指向合适的值。那么这种初始化的工作由谁来做呢?我们可以分别为两个类写初始化函数,类似于C++和Java中的构造函数,同时,在必要的时候我们也可以写出它们的析构函数用来释放内存空间。完整的例子如下:

#include

#include

struct Base {

int data;

int (*getData)( struct Base * );

};

struct Sub {

struct Base base;

int (*getData)( struct Sub * );

int data;

};

int getDataForBase( struct Base * base ) {

return base->data;

}

int getDataForSubBase( struct Base * base ) {

return ((struct Sub *)base)->data;

}

int getDataForSub( struct Sub * sub ) {

/*这个函数和上面的函数只有参数类型不同。

* 如果代码太长我们可以直接调用上面的函数。

* 我们也可以省略这个函数而把 sub 中的函数指针

* 设成和 Base 类相同,这样在调用时如果传递 sub

* 指针,那么编译器会发出警告。*/

return sub->data;

}

/* Base 的“构造函数” */

void Base_init( struct Base * base ) {

base->data = 3;

base->getData = getDataForBase;

}

/* Sub 的“构造函数” */

void Sub_init( struct Sub * sub ) {

Base_init( (struct Base*)sub );        /* 在C++中,子类的构造方法默认将调用父类的无参数构造方法。*/

((struct Base*)sub)->getData = getDataForSubBase;/* 设置函数指针 */

sub->getData = getDataForSub;        /* 设置函数指针 */

sub->data = 5;

}

/* Base 和 Sub 的析构函数: */

void Base_destroy( struct Base * base) {}

void Sub_destroy( struct Sub * sub) {}

int main()

{

struct Base * base = (struct Base*)malloc(sizeof(struct Base));

Base_init(base);

struct Sub * sub = (struct Sub*)malloc(sizeof(struct Sub));

Sub_init(sub);

struct Base * subbase = (struct Base*)sub;

/*从下面的语句可以看出,不论是 Base 型的指针指向 Base 型,Base 型指针指向 Sub 型,还是 Sub 型指针指向 Sub 型,调用函数的格式都是统一的。*/

printf( "%d\n%d\n%d\n", base->getData(base), sub->getData(sub), subbase->getData(subbase) );

free(base);        /*适当地换成析构函数*/

free(sub);        /*适当地换成析构函数*/

}

这样实现动态连接的类显然就不能通过切割内存来实现类型转换了,如果试图把一个Sub类强行切割成Base类,那么得到的Base类中的函数指针就可能指向错误的函数。我们必须在切割之后重新设置Base中函数指针的值。

讨论过这些之后,我们设想一下在C语言中可不可以实现数据结构和算法的通用函数。在以前学习C语言的时候,即使是简单的单链表操作,在一个程序中实现的操作函数也不能直接拿到另一个程序中使用,因为链表的节点结构不同。而现在,只要定义一个基本的节点模板:

struct listNode {

struct listNode * next;

};

我们就可以写出针对它的操作函数。而在使用时,我们定义一个继承它的类:

struct myListNode {

struct listNode node;

int data;

};

通过强制类型转换,就可以使用通用函数了。用这种方法可以实现链表的创建、插入、删除等操作的通用函数。如果要在链表中查找指定的节点呢?运用函数指针将判别函数传入通用函数,这样查找也实现了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值