C语言实现面向对象之继承性

来源:互联网 发布:有没有像淘宝助理 编辑:程序博客网 时间:2024/06/06 03:17
面向对象有三个最为明显的特性:继承、封装、多态性。C++、java、C#等面向对象语言在语言层次上支持OOP,而OOP本身其实并不是专门为语言设计的。虽然C语言在语言层次上不支持面向对象,但是通过C语言也是可以实现OOP的特性的。

下面就主要讲述通过C语言实现面向对象的三大特性之一:继承性。

“继承”是面向对象中的一个概念,如果一个类A继承自另一个类B,就把这个类A称之为类B的子类,而B类则是A的父类。继承使得子类具有了父类的各种属性和方法,而不需要重新编写这些方法。同时,子类也可以重新定义一些属性,或者追加一些新的功能和属性。

在C++语言中,个派生类可以从一个基类派生,也可以从多个基类派生。从一个基类派生的继承称为单继承;从多个基类派生的继承称为多继承。

继承的定义格式如下:

  class <派生类名>:<继承方式><基类名>

  {

  <派生类新定义成员>

};

一般对于继承方式有三类,公有继承、私有继承、保护继承。

(1)     公有继承:基类成员对派生类的可见性对派生类来说,基类的公有成员和保护成员可见:基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态;基类的私有成员不可见:基类的私有成员仍然是私有的,派生类不可访问基类中的私有成员。

(2)     私有继承:基类成员对派生类的可见性对派生类来说,基类的公有成员和保护成员是可见的:基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问;基类的私有成员是不可见的:派生类不可访问基类中的私有成员。对派生类对象来说,基类的所有成员都是不可见的。所以,在私有继承时,基类的成员只能由直接派生类访问,而无法再往下继承。

(3)     保护继承:这种继承方式与私有继承方式的情况相同。两者的区别仅在于对派生类的成员而言。基类成员对派生类的可见性对派生类来说,基类的公有成员和保护成员是可见的,基类的公有成员和保护成员都作为派生类的保护成员,并且不能被这个派生类的子类所访问。基类的私有成员是不可见的,派生类不可访问基类中的私有成员。对派生类对象来说,基类的所有成员都是不可见的。所以,在保护继承时,基类的成员也只能由直接派生类访问,而无法再往下继承。

上节提到了面向对象中的继承性的概念,而面向对象是一种设计思想,这种思想并不是针对某种语言的。通过C语言也是可以实现面向对象中的继承性这一个特点的。

用C语言实现继承一般有2种方法:声明放在结构中,声明在结构外。另外还有一种方法是:用宏定义出C++,但是这种方法在使用上很不方便,同时也不便于理解,所以在此就不介绍了。

这种方法是通过将父类的方法声明在一个结构体中,然后在声明子类的结构体中引用父类的结构体,以达到类似继承的作用。具体的实施过程如示例:

[cpp] view plaincopy
  1. typedef StructMySuperClassTag{  
  2.     intx;      //属性声明  
  3.    voidf(void);//方法声明,在结构中。  
  4. }MySuperClass;  
  5. typedef StructMyClassTag{  
  6.    MySuperClass  super    //继承自父类,一定要放在最前边  
  7.     int y;      //增加的属性声明  
  8.     voidg(void);//增加的方法声明  
  9. }MySuperClass;  

如上例中,父类的实现方法定义在一个结构体中,子类需要继承父类则需要在自己的结构体中也定义一个父结构,以便自己来继承。但是这种方法有一定的局限性。

这种方法没有在父类中体现出成员访问权限的区分,而且对于父类的数据成员的保护也很难能够做好。但是这种实现方式易于理解,操作简单。

将父类的实现方法放在结构体之外,这种是将实现方法和属性相互分开的一种方式。在父类的实现方法上的过程中,父类的结构体指针充当一个参数的作用。这样,便将父类的结构体与其实现方法进行了关联。

a)        定义父类的属性为结构体,属性是提供继承的。

b)       用一个属性结构体的指针作为父类的成员方法的参数,从而将属性和成员方法关联起来。

c)        因为成员方法的实现是在结构体之外的,所以方法的继承和属性的继承是分开的。父类的成员方法的继承通过宏定义实现控制,而访问的权限也可以进行控制。

d)       当子类继承了父类的属性和方法之后,还可以自行添加方法以及属性。

具体的示例如下:

[cpp] view plaincopy
  1. //父类属性结构体  
  2. Typedef structParentTag{  
  3. //父类的属性说明  
  4. }Parent;//只包含属性  
  5. //父类实现方法  
  6. #defineP_ctor(me,par)    //构造函数为抽象类,通过宏定义进行声明  
  7. Void P_method1(Parentme,int parameter)  
  8. Void P_method2(Parentme,float parameter)  
  9. //子类属性结构体  
  10. Typedef structChildTag{  
  11. //子类的属性  
  12. Struct Parent father;  
  13. ……;  
  14.    
  15. }child;  
  16. //子类的成员方法  
  17. //继承父类的方法  
  18. #define Child_P_ctor(me,typeparameter1)   //继承构造函数  
  19. #defineChild_P_method1(me,type parameter2)// 继承成员函数  
  20. #defineChild_P_method2(me,type parameter3)// 继承成员函数  
  21. //追加的成员函数实现方法  
  22. Void Child_ctor(Child*me,type parameter1);  
  23. VoidChild_method1(Child *me,type parameter2);  
  24. …  

从上面的例子中可以看到,和第一种方式相比较而言,通过将父类的属性和方法分开,从而可以实现子类在对父类进行继承时候的访问权限的控制。

同时,通过宏定义实现对父类的方法的继承对于数据的封装也有很好的作用,同时在操作上也很容易实现。子类也可以在父类的基础上继续追加自定义的成员方法。而且在继承的成员函数和追加的成员函数上使用都不会造成不便的影响。

继承性作为面向对象的三大特性之一,虽然C语言是面向过程化的程序语言,但是利用C语言也可以实现面向对象的所有特性。下面就会讲到利用C语言实现面向对象的另外一些特性,封装和多态。

原创粉丝点击