用C语言模拟面向对象编程(上)

简介: 用C语言模拟面向对象编程(上) 导读:    用C语言模拟面向对象编程    虽然我接触计算机已经有将近一年了,但一直以来我不愿意写技术方面的文档,因为所谓的“技术”就是照着做得东西, 即使可能遇到一些难题,到网上搜索一下就可以解决,不值得把网上长篇累牍的文档复制粘贴到这里来。

用C语言模拟面向对象编程(上)


导读: 
  用C语言模拟面向对象编程 
  虽然我接触计算机已经有将近一年了,但一直以来我不愿意写技术方面的文档,因为所谓的“技术”就是照着做得东西, 即使可能遇到一些难题,到网上搜索一下就可以解决,不值得把网上长篇累牍的文档复制粘贴到这里来。即使是自己写,也是写些别人已经解决过的东西。所以不论是数学,还是计算机,在这里我没有写过那种简单搬运知识的文章。 
  但即使再纯粹的技术,弄得时间长了都会产生一些独特的想法和感受,记录这些想法可能不光对自己是有意义的。今天来写第一篇偏向技术的东西。 
  如何在C语言中用面向对象的思路写程序?这已经是很多人考虑过的问题了,而且实际上已经有人在用C语言实现一些面向对象的项目了,比如,在Linux下大名鼎鼎的图形界面GNOME,就是通过C语言模拟的面向对象特性来实现的。 
  在一本名叫《面向对象编程,C++和Java比较教程》的书中有一个抛砖引玉的例子,代码如下(见该书中文版第67页,其中注释块中是自己的评注): 
  /* SimulatedOO.c */ 
  #include 
  #include 
  #include 
  /* 基类型: */ 
  typedef struct 
  { 
  char * name; 
  int age; 
  } User; 
  /* 子类型: */ 
  typedef struct 
  { 
  User genericUser; 
  char ** listOfCourses; 
  int numCourses; 
  int whatYear; 
  } StudentUser; 
  /********************************************************* 
  * 这样, 在子类型 StudentUser 中就有一个基类 User 的结构体 
  * 变量, 并且在内存中 User 结构体占据 StudentUser 的开头部分, 
  * 这样,把一个指向 StudentUser 类型的指针强制类型转换到 User* 
  * 类型,就可以访问到 User 的相应区域,这样就实现了继承机制。 
  ********************************************************/ 
  /* 为基类型User定义的函数: */ 
  void setUserName( User* user,char aName[] ) { 
  user -> name = malloc(strlen(aName)+1); /* 原文为 malloc( sizeof(strlen(aName)+1) ), 这是不正确的。*/
  strcpy(user->name,aName); 
  } 
  /* 为基类型User定义的函数: */ 
  char * getUserName( User * user) { 
  printf("/nName of user: %s/n",user->name); 
  return user->name; 
  } 
  /* 为基类型User定义的函数: */ 
  void setUserAge(User * user,int yy) { 
  user -> age=yy; 
  } 
  /* 为基类型User定义的函数: */ 
  int getUserAge( User * user ) { 
  printf("%s's age: %d/n",user->name,user->age); 
  return user-> age; 
  } 
  /* 为基类型User定义的函数: */ 
  /************************************************** 
  * 这个函数在书中是用来展示多态行为的,不过这种实现多态的 
  * 方式并不是很好,并不能实现类似于C++或Java中多态的动态连 
  * 接机制。具体用法见主程序中注释为“多态行为” 那两行。 
  *************************************************/ 
  int isSenior( User * user ) { 
  if ( user->age >70 ) return 1; 
  else return 0; 
  } 
  /* 为子类型 StudentUser 定义的函数: */ 
  void setListOfCourses( StudentUser* student,char* listCrs[],int nCourses) { 
  int i; 
  char ** temp; 
  student->numCourses = nCourses; 
  temp = malloc( nCourses * sizeof( char* )); 
  student->listOfCourses=temp; 
  for(i=0;i numCourses;i++) { 
  *temp = malloc( strlen( *listCrs )+1); 
  strcpy(*temp,*listCrs); 
  *temp++; 
  listCrs++; 
  } 
  } 
  /* 为子类型 StudentUser 定义的函数: */ 
  void printListOfCourses( StudentUser * student ) { 
  int i; 
  char ** temp; 
  temp = student->listOfCourses; 
  printf("/n%s's courses: /n",student->genericUser.name); 
  for(i=0;i numCourses;i++) 
  printf("%s/n",*(temp++)); 
  } 
  /* 为子类型 StudentUser 定义的函数: */ 
  void setYear( StudentUser* student,int yy) { 
  student->whatYear=yy; 
  } 
  /* 为子类型 StudentUser 定义的函数: */ 
  int getYear( StudentUser* student) { 
  return student->whatYear; 
  } 
  int main() 
  { 
  User * zaphod; 
  StudentUser* trillian; 
  char * listCourses[]={"Physics","Chemistry","algebra"}; 
  int numCrs = sizeof(listCourses)/sizeof(listCourses[0]); 
  zaphod = malloc(sizeof(User)); 
  setUserName(zaphod,"Zaphod"); 
  setUserAge(zaphod,89); 
  getUserName(zaphod); 
  getUserAge(zaphod); 
  trillian=malloc(sizeof(StudentUser)); 
  setUserName((User*)trillian,"Trillian" ); 
  setUserAge((User*)trillian,18); 
  getUserName((User*)trillian); 
  getUserAge((User*)trillian); 
  setListOfCourses(trillian,listCourses,numCrs); 
  printListOfCourses(trillian); 
  /*  多态行为 */ 
  printf("/nZaphod is senior is %s/n",isSenior(zaphod)? "true":"false"); 
  printf("/nTrillian is senior is %s/n", isSenior((User*)trillian)? "true":"false"); 
  /***************************************************** 
  * 和setUserAge 、setUserName之类的函数一样,isSenior 
  * 需要一个基类指针参数,通过将 trillian 转换为 User* 
  * 类型,就会把指向trillian 中User域的指针传进函数。 
  * ***************************************************/ 
  printf("name field of trillian is at address: %p/n", &( trillian->genericUser.name )); 
  printf("trillian when cast to User* is at address: %p/n",(User*)trillian ); 
  /*************************************************** 
  * 这两行输出的地址值是一样的。 
  * *************************************************/ 
  } 
  在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中也实现类似的功能呢? (待续) 

本文转自 
http://blog.csdn.net/chief1985/article/details/2008479
http://blog.blogwhy.com/tpfly/e_23482.html

目录
相关文章
|
14天前
|
程序员 C语言
C语言库函数 — 内存函数(含模拟实现内存函数)
C语言库函数 — 内存函数(含模拟实现内存函数)
24 0
|
25天前
|
编译器 C语言 C++
【C语言】memset()函数(内存块初始化函数)
【C语言】memset()函数(内存块初始化函数)
26 0
|
25天前
|
编译器 C语言 C++
【C语言】memcpy()函数(内存块拷贝函数)
【C语言】memcpy()函数(内存块拷贝函数)
42 0
|
26天前
|
C语言 C++
【C语言】rand()函数(如何生成指定范围随机数)
【C语言】rand()函数(如何生成指定范围随机数)
16 0
|
1月前
|
C语言
在C语言中数组作为函数参数的应用与示例
在C语言中数组作为函数参数的应用与示例
15 0
|
1天前
|
存储 C语言
C语言函数的返回值
C语言函数的返回值
6 0
|
1天前
|
C语言 Windows
C语言中的fopen与fclose函数详解
C语言中的fopen与fclose函数详解
6 1
|
1天前
|
C语言
深入理解C语言中的printf函数及数据输出
深入理解C语言中的printf函数及数据输出
8 0
|
14天前
|
程序员 C语言 开发者
C语言库函数 — 字符串函数(含模拟实现字符串函数)
C语言库函数 — 字符串函数(含模拟实现字符串函数)
35 0
|
20天前
|
存储 C语言
【我爱C语言】详解字符函数isdigit和字符串转换函数(atoi和snprintf实现互相转换字符串)&&三种strlen模拟实现1
【我爱C语言】详解字符函数isdigit和字符串转换函数(atoi和snprintf实现互相转换字符串)&&三种strlen模拟实现