C实现类封装、继承、多态

1、  概述

 

C语言是一种面向过程的程序设计语言,而C++是在C语言基础上衍生来了的面向对象的语言,实际上,很多C++实现的底层是用C语言实现的,如在Visual C++中的Interface其实就是struct,查找Interface的定义,你可以发现有这样的宏定义:

#ifndef Interface

#define Interface struct

#endif

C++在语言级别上添加了很多新机制(继承,多态等),而在C语言中,我们也可以使用这样的机制,前提是我们不得不自己实现。

本文介绍了用C语言实现封装,继承和多态的方法。

2、  基本知识

在正式介绍C语言实现封装,继承和多态事前,先介绍一下C语言中的几个概念和语法。

(1)    结构体

在C语言中,常把一个对象用结构体进行封装,这样便于对对象进行操作,比如:

1

2

3

4

5

6

7

strcut Point{

 

int x;

 

int y;

 

};

结构体可以嵌套。因而可以把一个结构体当成另一个结构体的成员,如:

1

2

3

4

5

6

7

struct Circle {

 

struct Point point_;

 

int radius;

 

};

该结构体与以下定义完全一样(包括内存布置都一样):

1

2

3

4

5

6

7

8

9

struct Circle {

 

int x;

 

int y;

 

int radius;

 

};

(2)    函数指针

函数指针是指针的一种,它指向函数的首地址(函数的函数名即为函数的首地址),可以通过函数指针来调用函数。

如函数:

int func(int a[], int n);

可以这样声明函数指针:

int (*pFunc)(int a[], int n);

这样使用:

pFunc = func;

(*pFunc)(a, n);【或者PFunc(a, n)】

可以用typedef定义一个函数指针类型,如:

typdef int (*FUNC)(int a[], int n)

可以这样使用:

int cal_a(FUNC fptr, int a[], int n)

{

//实现体

}

(3)    extern与static

extern和static是C语言中的两个修饰符,extern可用于修饰函数或者变量,表示该变量或者函数在其他文件中进行了定义;static也可用于修饰函数或者变量,表示该函数或者变量只能在该文件中使用。可利用它们对数据或者函数进行隐藏或者限制访问权限。

3、  封装

在C语言中,可以用结构+函数指针来模拟类的实现,而用这种结构定义的变量就是对象。

封装的主要含义是隐藏内部的行为和信息,使用者只用看到对外提供的接口和公开的信息。有两种方法实现封装:

(1)    利用C语言语法。在头文件中声明,在C文件中真正定义它。

这样可以隐藏内部信息,因为外部不知道对象所占内存的大小,所以不能静态的创建该类的对象,只能调用类提供的创建函数才能创建。这种方法的缺陷是不支持继承,因为子类中得不到任何关于父类的信息。如:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

//头文件:point.h

 

#ifndef POINT_H

 

#define POINT_H

 

struct Point;

 

typedef struct Point point;

 

point * new_point(); //newer a point object

 

void free_point(point *point_);// free the allocated space

 

#endif

 

//C文件:point.c

 

#include”point.h”

 

strcut Point

 

{

 

int x;

 

int y;

 

};

 

point * new_point()

 

{

 

point * new_point_ = (point *) malloc(sizeof(point));

 

return new_point_;

 

}

 

void free_point(point *point_)

 

{

 

if(point_ == NULL)

 

return;

 

free(point_);

 

}

(2)    把私有数据信息放在一个不透明的priv变量或者结构体中。只有类的实现代码才知道priv或者结构体的真正定义。如:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

#ifndef POINT _H

 

#define POINT_H

 

typedef struct Point point;

 

typedef struct pointPrivate pointPrivate;

 

strcut Point

 

{

 

Struct pointPrivate *pp;

 

};

 

int get_x(point *point_);

 

int get_y(point *point_);

 

point * new_point(); //newer a point object

 

void free_point(point *point_);// free the allocated space

 

#endif

 

//C文件:point.c

 

#include”point.h”

 

struct pointPrivate

 

{

 

int x;

 

int y;

 

}

 

int get_x(point *point_)

 

{

 

return point_->pp->x;

 

}

 

int get_y(point *point_)

 

{

 

return point_->pp->y;

 

}

 

//others…..

4、  继承

在C语言中,可以利用“结构在内存中的布局与结构的声明具有一致的顺序”这一事实实现继承。

比如我们要设计一个作图工具,其中可能涉及到的对象有Point(点),Circle(圆),由于圆是由点组成的,所有可以看成Circle继承自Point。另外,Point和Circle都需要空间申请,空间释放等操作,所有他们有共同的基类Base。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

//内存管理类new.h

 

#ifndef NEW_H

 

#define NEW_H

 

void * new (const void * class, ...);

 

void delete (void * item);

 

void draw (const void * self);

 

#endif

 

//内存管理类的C文件:new.c

 

#include “new.h”

 

#include “base.h”

 

void * new (const void * _base, ...)

 

{

 

const struct Base * base = _base;

 

void * p = calloc(1, base->size);

 

assert(p);

 

* (const struct Base **) p = base;

 

if (base ->ctor)

 

{

 

va_list ap;

 

va_start(ap, _base);

 

p = base ->ctor(p, &ap);

 

va_end(ap);

 

}

 

return p;

 

}

 

void delete (void * self)

 

{

 

const struct Base ** cp = self;

 

if (self && * cp && (* cp) —> dtor)

 

self = (* cp) —>dtor(self);

 

free(self);

 

}

 

void draw (const void * self)

 

{

 

const struct Base * const * cp = self;

 

assert(self &&* cp && (* cp)->draw);

 

(* cp) ->draw(self);

 

}

 

//基类:base.h

 

#ifndef BASE_H

 

#define BASE_H

 

struct Base

 

{

 

size_t size; //类所占空间

 

void * (* ctor) (void * self, va_list * app); //构造函数

 

void * (* dtor) (void * self); //析构函数

 

void (* draw) (const void * self); //作图

 

};

 

#endif

 

//Point头文件(对外提供的接口):point.h

 

#ifndef   POINT_H

 

#define  POINT_H

 

extern const void * Point;                /* 使用方法:new (Point, x, y); */

 

#endif

 

//Point内部头文件(外面看不到):point.r

 

#ifndef POINT_R

 

#define POINT_R

 

struct Point

 

{

 

const void * base; //继承,基类指针,放在第一个位置,const是防止修改

 

int x, y;        //坐标

 

};

 

#endif

 

//Point的C文件:point.c

 

#include “point.h”

 

#include “new.h”

 

#include “point.h”

 

#include “point.r”

 

static void * Point_ctor (void * _self, va_list * app)

 

{

 

struct Point * self = _self;

 

self ->x = va_arg(* app, int);

 

self ->y = va_arg(* app, int);

 

return self;

 

}

 

static void Point_draw (const void * _self)

 

{

 

const struct Point * self = _self;

 

printf(“draw (%d,%d)”, self -> x, self -> y);

 

}

 

static const struct Base _Point = {

 

sizeof(struct Point), Point_ctor, 0, Point_draw

 

};

 

const void * Point = & _Point;

 

//测试程序:main.c

 

#include “point.h”

 

#include “new.h”

 

int main (int argc, char ** argv)

 

{

 

void * p = new(Point, 1, 2);

 

draw(p);

 

delete(p);

 

}

同样,Circle要继承Point,则可以这样:

1

2

3

4

5

6

7

8

9

struct Circle

 

{

 

const struct Point point; //放在第一位,可表继承

 

int radius;

 

};

5、  多态

可以是用C语言中的万能指针void* 实现多态,接上面的例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

//测试main.c

 

void * p = new(Point, 1, 2);

 

void * pp = new(Circle, 1, 2);

 

draw(p); //draw函数实现了多态

 

draw(pp);

 

delete(p);

 

delete(pp);

6、  总结

C语言能够模拟实现面向对象语言具有的特性,包括:多态,继承,封装等,现在很多开源软件都了用C语言实现了这几个特性,包括大型开源数据库系统postgreSQL,可移植的C语言面向对象框架GObject,无线二进制运行环境BREW。采用C语言实现多态,继承,封装,能够让软件有更好的可读性,可扩展性。

7、  参考资料

(1)        《C语言中extern和static用法》:

http://www.cnblogs.com/hishope/archive/2008/08/28/1278822.html

(2)        《三、使用GObject——私有成员和静态变量》:

http://blog.youkuaiyun.com/wormsun/archive/2009/11/25/4874465.aspx

(3)        《技巧:用 C 语言实现程序的多态性》:

http://www.ibm.com/developerworks/cn/linux/l-cn-cpolym/index.html?ca=drs-

(4)        书籍《Object-Oriented Programming With ANSI-C》

8、  代码下载

本文中的代码可以在此处下载:代码下载

分类: 编程语言

转载于:https://my.oschina.net/u/4000302/blog/3020103

在Java中,封装继承多态是面向对象编程的三个重要概念。 1. 封装(Encapsulation):封装是将相关的变量和方法组合在一个单元(类)中,通过访问修饰符来控制外部对内部数据和方法的访问。这样可以隐藏内部实现细节,提高代码的安全性和可维护性。 示例代码: ```java public class Person { private String name; // 私有属性 private int age; public String getName() { // 公有方法 return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } ``` 2. 继承(Inheritance):继承是通过创建一个新类来扩展已有类的功能。子类继承了父类的属性和方法,并可以添加自己的特性。继承可以提高代码的重用性和可扩展性。 示例代码: ```java public class Student extends Person { private String school; public String getSchool() { return school; } public void setSchool(String school) { this.school = school; } } ``` 3. 多态(Polymorphism):多态允许使用一个父类类型的引用来引用子类对象,根据具体对象的类型调用相应的方法。多态可以提高代码的灵活性和可扩展性。 示例代码: ```java public class Main { public static void main(String[] args) { Person person = new Student(); // 使用父类类型的引用指向子类对象 person.setName("Tom"); person.setAge(20); System.out.println(person.getName()); // 调用子类的方法 } } ``` 以上是Java中封装继承多态的简单示例。通过封装继承多态的使用,可以更好地组织和管理代码,提高代码的可读性和可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值