C言語によるオブジェクトへの継承性の実現

3613 ワード

オブジェクト向けには、継承、パッケージング、マルチステートの3つの最も顕著な特性があります.C++、java、C#などのオブジェクト向け言語は言語階層でOOPをサポートしているが、OOP自体は言語専用ではない.C言語は言語階層ではオブジェクト向けをサポートしていないが,C言語でもOOPの特性を実現できる.
以下では主にC言語によるオブジェクト向けの3つの特性の1つである継承性について述べる.
「継承」はオブジェクト向けの概念であり、あるクラスAが別のクラスBから継承された場合、このクラスAをクラスBの子クラスと呼び、BクラスはAの親である.継承により、子クラスは親クラスの様々な属性とメソッドを有し、これらのメソッドを再記述する必要はありません.また、サブクラスでは、いくつかの属性を再定義したり、新しい機能や属性を追加したりすることもできます.
C++言語では、1つのベースクラスから派生してもよいし、複数のベースクラスから派生してもよい.1つのベースクラスから派生した継承を単一継承と呼ぶ.複数のベースクラスから派生した継承をマルチ継承と呼ぶ.
継承の定義形式は次のとおりです.
class<派生クラス名>:<継承方式><ベースクラス名>
  {
<派生クラス新規定義メンバー>
};
一般的に相続方式には3種類あり、公有相続、私有相続、保護相続がある.
(1)共有継承:派生クラスに対するベースクラスメンバーの可視性派生クラスに対して、ベースクラスの共有メンバーと保護メンバーが表示されます.ベースクラスの共有メンバーと保護メンバーが派生クラスのメンバーとして使用される場合、それらはすべて元の状態を維持します.ベースクラスのプライベートメンバーは表示されません.ベースクラスのプライベートメンバーは依然としてプライベートであり、派生クラスはベースクラスのプライベートメンバーにアクセスできません.
(2)プライベート継承:派生クラスに対するベースクラスメンバーの可視性派生クラスにとって、ベースクラスのパブリックメンバーと保護メンバーは可視である:ベースクラスのパブリックメンバーと保護メンバーはいずれも派生クラスのプライベートメンバーとして機能し、この派生クラスのサブクラスにアクセスできない;ベースクラスのプライベートメンバーは表示されません.派生クラスはベースクラスのプライベートメンバーにアクセスできません.派生クラスオブジェクトでは、ベースクラスのすべてのメンバーは表示されません.したがって、プライベート継承では、ベースクラスのメンバーは直接派生クラスからのみアクセスでき、これ以上継承できません.
(3)保護相続:この相続方式は私有相続方式の場合と同様である.両者の違いは、派生クラスのメンバーにとってのみです.ベースクラスメンバーの派生クラスに対する可視性派生クラスでは、ベースクラスの共有メンバーと保護メンバーが表示され、ベースクラスの共有メンバーと保護メンバーは派生クラスの保護メンバーとして機能し、この派生クラスのサブクラスにアクセスできません.ベースクラスのプライベートメンバーは表示されず、派生クラスはベースクラスのプライベートメンバーにアクセスできません.派生クラスオブジェクトでは、ベースクラスのすべてのメンバーは表示されません.したがって、継承を保護する場合、ベースクラスのメンバーも直接派生クラスからのみアクセスでき、これ以上継承できません.
前節では,オブジェクト向けの継承性の概念について述べたが,オブジェクト向けはある言語に対するものではない設計思想である.C言語によってもオブジェクトへの継承性が実現できるという特徴がある.
継承をC言語で実現するには、一般的に2つの方法があります.宣言は構造の外に置かれ、宣言は構造の外に置かれます.もう1つの方法は、マクロでC++を定義する方法ですが、この方法は使い勝手が悪く、理解しにくいので、ここでは紹介しません.
この方法は、親クラスのメソッドを1つの構造体に宣言し、子クラスを宣言する構造体で親クラスの構造体を参照することで、類似した継承の役割を果たします.実施例:
typedef StructMySuperClassTag{
    intx;      //    
   voidf(void);//    ,    。
}MySuperClass;
typedef StructMyClassTag{
   MySuperClass  super    //     ,        
    int y;      //       
    voidg(void);//       
}MySuperClass;

前の例のように、親の実装方法は構造体で定義され、子が親を継承する必要がある場合は、自分の構造体でも親構造を定義して、自分で継承する必要があります.しかし、この方法には一定の限界がある.
この方法では,親クラスにメンバーアクセス権の区別が現れず,親クラスのデータメンバーの保護も容易ではない.しかし、この実現方式は理解しやすく、操作が簡単である.
親クラスのインプリメンテーションメソッドを構造体の外に配置します.これは、インプリメンテーションメソッドと属性を互いに分離する方法です.親の実装方法では、親の構造体ポインタがパラメータとして機能します.これにより,親クラスの構造体とその実装方法が関連付けられる.
a)親クラスの属性を構造体として定義し、属性は継承を提供する.
b)属性構造体のポインタを親のメンバーメソッドのパラメータとして使用し、属性とメンバーメソッドを関連付ける.
c)メンバメソッドの実装は構造体の外にあるため,メソッドの継承と属性の継承は別々である.親クラスのメンバーメソッドの継承はマクロ定義によって制御され、アクセス権も制御されます.
d)子クラスが親クラスの属性とメソッドを継承した後、メソッドおよびプロパティを自分で追加することもできる.
具体的な例は次のとおりです.
//       
Typedef structParentTag{
//       
}Parent;//     
//      
#defineP_ctor(me,par)    //        ,         
Void P_method1(Parentme,int parameter)
Void P_method2(Parentme,float parameter)
//       
Typedef structChildTag{
//     
Struct Parent father;
……;
 
}child;
//       
//       
#define Child_P_ctor(me,typeparameter1)   //      
#defineChild_P_method1(me,type parameter2)//       
#defineChild_P_method2(me,type parameter3)//       
//           
Void Child_ctor(Child*me,type parameter1);
VoidChild_method1(Child *me,type parameter2);
…

上記の例から、第1の方法と比較して、親の属性と方法を分けることで、親を継承する際の子のアクセス権の制御を実現できることがわかる.
また,マクロ定義による親クラスへのメソッドの継承はデータのカプセル化にもよい役割を果たし,操作上も容易に実現できる.子クラスは、親クラスに基づいてカスタムメンバーメソッドを追加し続けることもできます.また継承されたメンバー関数や追加されたメンバー関数の使用にも不便な影響はありません.
継承性はオブジェクト向けの3つの特性の1つとして,C言語はプロセス化向けのプログラム言語であるが,C言語を用いてオブジェクト向けのすべての特性を実現することもできる.以下では,C言語を用いてオブジェクト向けの他の特性,パッケージング,マルチステートを実現する.