C++プログラミングにおける純虚関数と抽象クラスを深く解析する
7426 ワード
C++純虚関数の詳細
ベースクラスでメンバー関数を虚関数とする場合があり、ベースクラス自体の要件ではなく、派生クラスの必要性を考慮して、ベースクラスに関数名を予約し、具体的な機能は派生クラスに残して必要に応じて定義します.
純虚関数は、虚関数を宣言するときに「初期化」されて0になる関数です.純粋な虚関数を宣言する一般的な形式は
純虚関数について注意すべき点:純虚関数には関数体がない. の最後尾の"=0"は関数の戻り値が0であることを示さず、コンパイルシステムに「これは純粋な虚関数だ」と伝える形式的な役割を果たすだけである. これは宣言文で、最後にセミコロンが必要です.
純虚関数は関数の名前のみで関数の機能を備えておらず,呼び出されない.コンパイルシステムに通知されるのは、「派生クラスで定義される虚関数をここで宣言します」だけです.派生クラスでこの関数を定義してから、関数の機能を備え、呼び出すことができます.
純粋な虚関数の役割は、必要に応じて派生クラスを定義するために、ベースクラスに派生クラスの関数の名前を保持することです.
ベースクラスに関数名が保持されていない場合は、マルチステート性は実現できません.クラスに純虚関数が宣言され、その派生クラスに関数が定義されていない場合、その虚関数は派生クラスにおいて純虚関数のままです.
C++抽象クラスについて
クラスが宣言されている場合は、一般的にオブジェクトを定義できます.しかし、オブジェクト向けプログラミングでは、オブジェクトを生成するために使用されないクラスがあります.これらのクラスを定義する唯一の目的は、ベースクラスとして派生クラスを構築することです.これらは基本的なタイプとしてユーザーに提供され、ユーザーはこれに基づいて自分のニーズに応じて機能の異なる派生クラスを定義します.これらの派生クラスを使用してオブジェクトを作成します.
例えば、自動車メーカーは往々にして顧客にトラックのシャーシ(エンジン、伝動部分、車輪などを含む)を提供し、組立工場はそれをトラック、バス、工事車、客車などの異なる機能の車両に組み立てることができる.シャーシ自体は車両ではなく、加工を経て車両になるが、車両の基本的な構成部分である.ベースクラスに相当します.現代化の生産の中で、大部分は専門化の生産方式を採用して、専門の化学工場が生産した部品を十分に利用して、加工して新品種の製品に集積します.バスを生産するメーカーは決してエンジンの製造からタイヤの生産、車両の製造まで当工場で完成しない.実は、異なるブランドのパソコンの基本的な部品は同じか似ています.このような観念はソフトウェア開発にとって非常に重要である.優れたソフトウェア関係者は、大きなソフトウェアを開発する際に、最初から最後まで自分でプログラムコードを書くことはありません.彼は既存のリソース(クラスライブラリなど)を自分の仕事の基礎として十分に利用します.
このようなオブジェクトを定義するために使用されず、継承されたクラスとしてのみ使用される基本タイプであり、抽象クラス(abstract class)と呼ばれ、ベースクラスとしてよく使用されるため、一般的に抽象ベースクラス(abstract base class)と呼ばれる.純粋な虚関数を含むクラスはすべて抽象クラスである.純粋な虚関数は呼び出せないため、純粋な虚関数を含むクラスはオブジェクトを構築できません.
抽象クラスの役割は、クラスの共通のベースクラスとして、またはクラスに共通のインタフェースを提供することである.1つのクラス階層には、もちろん抽象的なクラスは含まれません.各階層のクラスは実際に使用でき、オブジェクトを構築するために使用できます.
しかし、多くの良いオブジェクト向けのシステムは、階層の上部が抽象クラスであり、上部にもいくつかの層が抽象クラスである.
抽象クラスから派生した新しいクラスでベースクラスのすべての純虚関数を定義すると,これらの関数には機能が与えられ,呼び出される.この派生クラスは抽象クラスではなく、オブジェクトの特定のクラス(concrete class)を定義するために使用できます.
派生クラスですべての純虚関数が定義されていない場合、この派生クラスは抽象クラスであり、オブジェクトを定義するために使用できません.抽象クラスはオブジェクトを定義できません(または抽象クラスはインスタンス化できません)が、抽象クラスデータを指すポインタ変数を定義できます.派生クラスが特定のクラスになると、このようなポインタで派生クラスオブジェクトを指し、そのポインタで虚関数を呼び出し、多態性の動作を実現することができる.
C++純虚関数と抽象クラスに関するいくつかの例は、以下の完全なプログラムであり、読みやすいように、セグメントにいくつかの文字の説明が挿入されています.手順は次のとおりです.
第(1)部
Shapeクラスには3つのメンバー関数があり、データメンバーはありません.3つのメンバー関数はすべて虚関数として宣言され、shapeNameは純虚関数として宣言されるため、Shapeは抽象ベースクラスである.ShapeName関数の役割は、点、円、円柱などの特定の形状の名前を出力することです.この情報は、対応する派生クラスと密接に関連しており、ベースクラスでは定義されず、派生クラスで定義されるべきであることは明らかです.だからそれを純虚関数として宣言します.Shapeは抽象ベースクラスですが、一部のメンバーの定義部分も含めることができます.クラスの2つの関数area(面積)とvolume(体積)は、点の面積と体積が0であると考えられるため、関数体を含む.Pointクラスではareaとvolume関数を再定義しないことを考慮したため,areaとvolume関数も純虚関数として宣言しなかった.PointクラスにはShapeクラスのareaとvolume関数が継承されています.この3つの関数は各派生クラスで使用されます.
第(2)部
PointはShapeから3つのメンバー関数を継承しており、「点」には面積と体積がないため、areaとvolumeを再定義する必要はありません.この2つの関数はPointクラスでは使用できませんが、派生クラスがそれらを継承するためにShapeクラスから継承されます.ShapeName関数はShapeクラスでは純虚関数であり、Pointクラスで定義されます.Pointクラスには、独自のメンバー関数(setPoint,getX,getY)とデータメンバー(xとy)があります.
第(3)部
Circleクラスでarea関数を再定義するには、円面積を求める式を指定する必要があるためです.円にはボリュームがないため、volume関数を再定義する必要はなく、Pointクラスからvolume関数を継承します.ShapeName関数は虚関数であり、再定義が必要であり、新しい内容を付与する必要がある(再定義しないとPointクラスのshapeName関数が継承される).また、Circleクラスには、独自に追加したメンバー関数(setRadius,getRadius)とデータメンバー(radius)があります.
パート4
CylinderクラスはCircleクラスから派生しています.円柱には表面積と体積があるため、areaとvolume関数を再定義します.ダミー関数shapeNameも再定義する必要があります.また、Cylinderクラスには、独自のメンバー関数setHeightとデータメンバーradiusがあります.
第(5)部
メイン関数で関連関数を呼び出し、結果を出力します.まず、Pointクラスオブジェクトpoint、Circleクラスオブジェクトcircle、Cylinderクラスオブジェクトcylinderをそれぞれ定義します.次に、オブジェクト名point、circle、およびcylinderによってshapename関数が呼び出されます.これは静的関連に属し、コンパイルフェーズでどのクラスを呼び出すべきかを決定するshapename関数です.同時に重荷重の演算子"<
ベースクラスShapeオブジェクトを指すポインタ変数ptを定義し、3つの派生クラスオブジェクトpoint、Circle、およびcylinderを前後して指し示すようにします.次に、pt->shapeName()、pt->area()、pt->volume()などの各関数をポインタで呼び出します.この場合,どの関数を呼び出すべきかを動的関連付けによりそれぞれ決定する.異なるクラスのオブジェクトの情報をそれぞれ出力します.
プログラムの実行結果は次のとおりです.
この例から、1つのベースクラスが1つ以上の純粋な虚関数を含む場合、抽象的なベースクラスであることをさらに明確にすることができる.抽象ベースクラスは、オブジェクトを定義する必要もありません.抽象ベースクラスは一般ベースクラスとは異なり、現実に存在するオブジェクトの抽象ではなく(例えば、円形(Circle)は数千万の実際の円の抽象であり、物理的または他の実際の意味の意味を持たないことができる.クラスの階層では、最上位または最上位の階層が抽象ベースクラスであってもよい.抽象ベースクラスは本クラスの各種類の共通性を体現し、各種類の中国共産党のあるメンバー関数を抽象ベースクラスに集中して声明した.抽象ベースクラスは、このクラスの共通インタフェースです.あるいは、同じベースクラスから派生した複数のクラスには、同じインタフェースがある.静的関連と動的関連を区別します.オブジェクト名で虚関数(point.shapeName()など)を呼び出す場合、コンパイルフェーズで呼び出されたクラスがどのクラスの虚関数であるかを決定できるため、静的関連付けに属します.ベースクラスポインタでダミー関数(pt->shapemame()など)を呼び出す場合、コンパイルフェーズで文自体からどのクラスのダミー関数を呼び出すかを決定することはできません.実行時にptがクラスオブジェクトを指し示すと、どのクラスのダミー関数を呼び出すかを決定することができ、動的に関連付けられます.ベースクラスで虚関数が宣言されている場合、派生クラスでは、派生クラスでvirtualで宣言されているかどうかにかかわらず、その関数と同じ関数名、関数タイプ、パラメータ個数、およびタイプを持つ関数が虚関数です.虚関数を使用すると、プログラムの拡張性が向上します.クラスの宣言をクラスの使用から分離します.これはクラスライブラリを設計するソフトウェア開発者にとって特に重要です.
開発者は様々なクラスを設計したが、ソースコードをユーザーに提供せず、ユーザーはクラスがどのように宣言されているか分からないが、これらのクラスを使用して自分のクラスを派生させることができる.虚関数と多態性を用いて,プログラマの注意力は普遍性の処理に集中し,実行環境の処理の特殊性をもたらす.
多態性は操作の細部をクラスの設計者(彼らは多く専門家である)に残して完成させ、プログラム人員(クラスの使用者)にマクロ的な仕事をして、システムに何をするかを教えるだけで、どのようにするかを考慮する必要はなく、アプリケーションのコード作業を極めて簡素化し、プログラマーの負担を大幅に軽減し、C++プログラミングの学習と使用の難しさを低減した.より多くの人がより速くC++プログラム設計の扉に入ることができます.
ベースクラスでメンバー関数を虚関数とする場合があり、ベースクラス自体の要件ではなく、派生クラスの必要性を考慮して、ベースクラスに関数名を予約し、具体的な機能は派生クラスに残して必要に応じて定義します.
純虚関数は、虚関数を宣言するときに「初期化」されて0になる関数です.純粋な虚関数を宣言する一般的な形式は
virtual ( ) = 0;
純虚関数について注意すべき点:
純虚関数は関数の名前のみで関数の機能を備えておらず,呼び出されない.コンパイルシステムに通知されるのは、「派生クラスで定義される虚関数をここで宣言します」だけです.派生クラスでこの関数を定義してから、関数の機能を備え、呼び出すことができます.
純粋な虚関数の役割は、必要に応じて派生クラスを定義するために、ベースクラスに派生クラスの関数の名前を保持することです.
ベースクラスに関数名が保持されていない場合は、マルチステート性は実現できません.クラスに純虚関数が宣言され、その派生クラスに関数が定義されていない場合、その虚関数は派生クラスにおいて純虚関数のままです.
C++抽象クラスについて
クラスが宣言されている場合は、一般的にオブジェクトを定義できます.しかし、オブジェクト向けプログラミングでは、オブジェクトを生成するために使用されないクラスがあります.これらのクラスを定義する唯一の目的は、ベースクラスとして派生クラスを構築することです.これらは基本的なタイプとしてユーザーに提供され、ユーザーはこれに基づいて自分のニーズに応じて機能の異なる派生クラスを定義します.これらの派生クラスを使用してオブジェクトを作成します.
例えば、自動車メーカーは往々にして顧客にトラックのシャーシ(エンジン、伝動部分、車輪などを含む)を提供し、組立工場はそれをトラック、バス、工事車、客車などの異なる機能の車両に組み立てることができる.シャーシ自体は車両ではなく、加工を経て車両になるが、車両の基本的な構成部分である.ベースクラスに相当します.現代化の生産の中で、大部分は専門化の生産方式を採用して、専門の化学工場が生産した部品を十分に利用して、加工して新品種の製品に集積します.バスを生産するメーカーは決してエンジンの製造からタイヤの生産、車両の製造まで当工場で完成しない.実は、異なるブランドのパソコンの基本的な部品は同じか似ています.このような観念はソフトウェア開発にとって非常に重要である.優れたソフトウェア関係者は、大きなソフトウェアを開発する際に、最初から最後まで自分でプログラムコードを書くことはありません.彼は既存のリソース(クラスライブラリなど)を自分の仕事の基礎として十分に利用します.
このようなオブジェクトを定義するために使用されず、継承されたクラスとしてのみ使用される基本タイプであり、抽象クラス(abstract class)と呼ばれ、ベースクラスとしてよく使用されるため、一般的に抽象ベースクラス(abstract base class)と呼ばれる.純粋な虚関数を含むクラスはすべて抽象クラスである.純粋な虚関数は呼び出せないため、純粋な虚関数を含むクラスはオブジェクトを構築できません.
抽象クラスの役割は、クラスの共通のベースクラスとして、またはクラスに共通のインタフェースを提供することである.1つのクラス階層には、もちろん抽象的なクラスは含まれません.各階層のクラスは実際に使用でき、オブジェクトを構築するために使用できます.
しかし、多くの良いオブジェクト向けのシステムは、階層の上部が抽象クラスであり、上部にもいくつかの層が抽象クラスである.
抽象クラスから派生した新しいクラスでベースクラスのすべての純虚関数を定義すると,これらの関数には機能が与えられ,呼び出される.この派生クラスは抽象クラスではなく、オブジェクトの特定のクラス(concrete class)を定義するために使用できます.
派生クラスですべての純虚関数が定義されていない場合、この派生クラスは抽象クラスであり、オブジェクトを定義するために使用できません.抽象クラスはオブジェクトを定義できません(または抽象クラスはインスタンス化できません)が、抽象クラスデータを指すポインタ変数を定義できます.派生クラスが特定のクラスになると、このようなポインタで派生クラスオブジェクトを指し、そのポインタで虚関数を呼び出し、多態性の動作を実現することができる.
C++純虚関数と抽象クラスに関するいくつかの例は、以下の完全なプログラムであり、読みやすいように、セグメントにいくつかの文字の説明が挿入されています.手順は次のとおりです.
第(1)部
#include
using namespace std;
// Shape
class Shape
{
public:
virtual float area( )const {return 0.0;} //
virtual float volume()const {return 0.0;} //
virtual void shapeName()const =0; //
};
Shapeクラスには3つのメンバー関数があり、データメンバーはありません.3つのメンバー関数はすべて虚関数として宣言され、shapeNameは純虚関数として宣言されるため、Shapeは抽象ベースクラスである.ShapeName関数の役割は、点、円、円柱などの特定の形状の名前を出力することです.この情報は、対応する派生クラスと密接に関連しており、ベースクラスでは定義されず、派生クラスで定義されるべきであることは明らかです.だからそれを純虚関数として宣言します.Shapeは抽象ベースクラスですが、一部のメンバーの定義部分も含めることができます.クラスの2つの関数area(面積)とvolume(体積)は、点の面積と体積が0であると考えられるため、関数体を含む.Pointクラスではareaとvolume関数を再定義しないことを考慮したため,areaとvolume関数も純虚関数として宣言しなかった.PointクラスにはShapeクラスのareaとvolume関数が継承されています.この3つの関数は各派生クラスで使用されます.
第(2)部
// Point
class Point:public Shape//Point Shape
{
public:
Point(float=0,float=0);
void setPoint(float ,float );
float getX( )const {return x;}
float getY( )const {return y;}
virtual void shapeName( )const {cout<
PointはShapeから3つのメンバー関数を継承しており、「点」には面積と体積がないため、areaとvolumeを再定義する必要はありません.この2つの関数はPointクラスでは使用できませんが、派生クラスがそれらを継承するためにShapeクラスから継承されます.ShapeName関数はShapeクラスでは純虚関数であり、Pointクラスで定義されます.Pointクラスには、独自のメンバー関数(setPoint,getX,getY)とデータメンバー(xとy)があります.
第(3)部
// Circle
class Circle:public Point
{
public:
Circle(float x=0,float y=0,float r=0);
void setRadius(float );
float getRadius( )const;
virtual float area( )const;
virtual void shapeName( )const {cout<
Circleクラスでarea関数を再定義するには、円面積を求める式を指定する必要があるためです.円にはボリュームがないため、volume関数を再定義する必要はなく、Pointクラスからvolume関数を継承します.ShapeName関数は虚関数であり、再定義が必要であり、新しい内容を付与する必要がある(再定義しないとPointクラスのshapeName関数が継承される).また、Circleクラスには、独自に追加したメンバー関数(setRadius,getRadius)とデータメンバー(radius)があります.
パート4
// Cylinder
class Cylinder:public Circle
{
public:
Cylinder (float x=0,float y=0,float r=0,float h=0);
void setHeight(float );
virtual float area( )const;
virtual float volume( )const;
virtual void shapeName( )const {
cout<
CylinderクラスはCircleクラスから派生しています.円柱には表面積と体積があるため、areaとvolume関数を再定義します.ダミー関数shapeNameも再定義する必要があります.また、Cylinderクラスには、独自のメンバー関数setHeightとデータメンバーradiusがあります.
第(5)部
//main
int main( )
{
Point point(3.2,4.5); // Point point
Circle circle(2.4,1.2,5.6);
// Circle circle
Cylinder cylinder(3.5,6.4,5.2,10.5);
// Cylinder cylinder
point.shapeName();
//
cout<shapeName( ); //
cout<area( )
<volume()<shapeName( ); //
cout<area( )
<volume( )<shapeName( ); //
cout<area( )
<volume( )<
メイン関数で関連関数を呼び出し、結果を出力します.まず、Pointクラスオブジェクトpoint、Circleクラスオブジェクトcircle、Cylinderクラスオブジェクトcylinderをそれぞれ定義します.次に、オブジェクト名point、circle、およびcylinderによってshapename関数が呼び出されます.これは静的関連に属し、コンパイルフェーズでどのクラスを呼び出すべきかを決定するshapename関数です.同時に重荷重の演算子"<
ベースクラスShapeオブジェクトを指すポインタ変数ptを定義し、3つの派生クラスオブジェクトpoint、Circle、およびcylinderを前後して指し示すようにします.次に、pt->shapeName()、pt->area()、pt->volume()などの各関数をポインタで呼び出します.この場合,どの関数を呼び出すべきかを動的関連付けによりそれぞれ決定する.異なるクラスのオブジェクトの情報をそれぞれ出力します.
プログラムの実行結果は次のとおりです.
Point:[3.2,4.5](Point point : )
Circle:[2.4,1.2], r=5.6 (Circle circle : )
Cylinder:[3.5,6.4], r=5.5, h=10.5 (Cylinder cylinder : 、 )
Point:x=3.2,y=4.5 ( Point point : )
area=0 ( )
volume=0 ( )
Circle:x=2.4,y=1.2 ( Circle circle : )
area=98.5203 ( )
volume=0 ( )
Cylinder:x=3.5,y=6.4 ( Cylinder cylinder : )
area=512.595 ( )
volume=891.96 ( )
この例から、1つのベースクラスが1つ以上の純粋な虚関数を含む場合、抽象的なベースクラスであることをさらに明確にすることができる.抽象ベースクラスは、オブジェクトを定義する必要もありません.抽象ベースクラスは一般ベースクラスとは異なり、現実に存在するオブジェクトの抽象ではなく(例えば、円形(Circle)は数千万の実際の円の抽象であり、物理的または他の実際の意味の意味を持たないことができる.クラスの階層では、最上位または最上位の階層が抽象ベースクラスであってもよい.抽象ベースクラスは本クラスの各種類の共通性を体現し、各種類の中国共産党のあるメンバー関数を抽象ベースクラスに集中して声明した.抽象ベースクラスは、このクラスの共通インタフェースです.あるいは、同じベースクラスから派生した複数のクラスには、同じインタフェースがある.静的関連と動的関連を区別します.オブジェクト名で虚関数(point.shapeName()など)を呼び出す場合、コンパイルフェーズで呼び出されたクラスがどのクラスの虚関数であるかを決定できるため、静的関連付けに属します.ベースクラスポインタでダミー関数(pt->shapemame()など)を呼び出す場合、コンパイルフェーズで文自体からどのクラスのダミー関数を呼び出すかを決定することはできません.実行時にptがクラスオブジェクトを指し示すと、どのクラスのダミー関数を呼び出すかを決定することができ、動的に関連付けられます.ベースクラスで虚関数が宣言されている場合、派生クラスでは、派生クラスでvirtualで宣言されているかどうかにかかわらず、その関数と同じ関数名、関数タイプ、パラメータ個数、およびタイプを持つ関数が虚関数です.虚関数を使用すると、プログラムの拡張性が向上します.クラスの宣言をクラスの使用から分離します.これはクラスライブラリを設計するソフトウェア開発者にとって特に重要です.
開発者は様々なクラスを設計したが、ソースコードをユーザーに提供せず、ユーザーはクラスがどのように宣言されているか分からないが、これらのクラスを使用して自分のクラスを派生させることができる.虚関数と多態性を用いて,プログラマの注意力は普遍性の処理に集中し,実行環境の処理の特殊性をもたらす.
多態性は操作の細部をクラスの設計者(彼らは多く専門家である)に残して完成させ、プログラム人員(クラスの使用者)にマクロ的な仕事をして、システムに何をするかを教えるだけで、どのようにするかを考慮する必要はなく、アプリケーションのコード作業を極めて簡素化し、プログラマーの負担を大幅に軽減し、C++プログラミングの学習と使用の難しさを低減した.より多くの人がより速くC++プログラム設計の扉に入ることができます.