C++クラスの継承のまとめ

5349 ワード

一、継承概念:オブジェクト向けプログラム設計でコードを多重化できる重要な手段であり、既存のクラス特性の基礎を維持して拡張し、機能を増やし、新しいクラスを生成し、派生クラスと呼ぶ.
フォーマットの定義:
3つの継承関係:public,protected,private
3つのメンバーアクセス制限子:public,protected,private(3つの継承関係と区別する必要があり、混同できない)
簡単なクラスを挙げる:B公有継承(public)とA,Bは派生クラス,Aはベースクラス
class A
{
public:
	void FunTest1()
	{
		cout<<"FunTest1"<<endl;
	}
	int _a1;
protected:
	int _a2;
private:
	int _a3;
};
class B:public A
{
public:
	void FunTest2()
	{
		cout<<"FunTest2"<<endl;
	}
private:
	int _b;
};

void FunTest()
{
	B b;
	b.FunTest1();
	b._a1=1;
}

継承方法とベースクラスメンバーのアクセス制限子の関係は次のように変化します.
まとめ:1.派生クラスは(いずれの継承方式においても)ベースクラス内のすべてのデータメンバーとメンバー関数を継承し、派生クラス内でベースクラスの公有(public)メンバーと保護(protected)メンバーにアクセスでき、ベースクラスのプライベート(private)メンバーは存在するが見えず、派生クラスは直接アクセスできない.
2.ベースクラスメンバーがクラス外で直接アクセスされたくないが、派生クラスでアクセスする必要がある場合はprotectedと定義する(すなわち、保護メンバー制限子は継承によって現れる).クラス外で派生クラスオブジェクトを定義すると、派生クラスのpublicメンバーにもアクセスできます.
3.public継承はインタフェース継承であり、is-aの原則を維持し、各親クラスで使用可能なメンバー対のサブクラスも使用可能である.各子クラスオブジェクトも親クラスオブジェクトであるからである.protetced/private継承は継承を実現するものであり、ベースクラスの一部のメンバーは完全にサブクラスインタフェースの一部ではなくhas-aの関係原則であるため、特殊でない場合はこの2つの継承関係は使用されず、一般的には公有継承が使用される.
4.キーワードclassを使用する場合のデフォルトの継承方式はprivate、structを使用する場合のデフォルトの継承方式はpublicですが、表示する書き出し継承方式が望ましいです.
二、派生クラスの構造関数と構造関数(呼び出し構造関数と実行関数体の2つの順序を区別する)
クラス継承関係の派生クラス呼び出しコンストラクタ順序:
派生クラス構築関数——>>ベースクラス構築関数(派生クラス初期化リストで呼び出される)
関数体の実行順序:
ベースクラスコンストラクション関数->>派生クラスコンストラクション関数(派生クラス初期化リストでベースクラスコンストラクション関数も呼び出されるため、ベースクラス関数体を先に実行します)
構造関数の順序を呼び出します.
派生クラス構造関数——>>ベースクラス構造関数
関数体の実行順序:
派生クラスの解析関数——>>ベースクラスの解析関数(1派生クラスのオブジェクトの中で自分だけのメンバーが作成するのが遅く、ライフサイクルが短く、2派生クラスは自分だけのメンバーを解析し、ベースクラスは自分だけのメンバーを解析し、両者は関係ありません)
たとえば、次のようになります.
class A
{
public:
	A()
	{
		cout<<"A()"<<endl;
	}
	~A()
	{
		cout<<"~A()"<<endl;
	}
	int _a1;
protected:
	int _a2;
private:
	int _a3;
};

class B:public A
{
public:
	B()
	{
		cout<<"B()"<<endl;
	}
	~B()
	{
		cout<<"~B()"<<endl;
	}
private:
	int _b;
};

void FunTest()
{
	B b;
}
VS 2010の実行結果は、派生クラスオブジェクトbがコンストラクタおよびコンストラクタを呼び出す関数体の実行順序として表示される.
注意:
1.ベースクラスにはデフォルトのコンストラクタがあり、派生クラスには定義コンストラクタが表示されず、コンパイラは派生クラスにデフォルトのコンストラクタを合成します.
2.ベースクラスにはデフォルトのコンストラクション関数がなく、派生クラスは初期化リストにベースクラス名とパラメータリストを明示的に与える必要があります.次のようになります.
class A
{
public:
	A(int a)
	{
		cout<<"A()"<<endl;
	}
};

class B:public A
{
public:
	B(int a)
		:A(a)
	{
		cout<<"B()"<<endl;
	}
};

void FunTest()
{
	B b(2);
}
3.ベースクラスにコンストラクション関数が定義されていない場合、派生クラスは定義せずにデフォルトのコンストラクション関数をすべて使用することもできます.
4.ベースクラスは、パラメトリック構造関数を定義し、派生クラスは構造関数を定義します.
三.継承と変換
≪同名非表示|同名Hide|oem_src≫:ベース・クラスが派生クラスと同じ名前の関数またはデータ・メンバーを持つ場合、クラス外の派生クラス・オブジェクトでベース・クラスの同名メンバーを呼び出すときに、ベース・クラスの役割ドメインを追加します.たとえば、次のようにします.
class A
{
public:
	void FunTest()
	{
		cout<<"A::FunTest()"<<endl;
	}
	int _a;
};
class B:public A
{
public:
	void FunTest()
	{
		cout<<"B::FunTest()"<<endl;
	}
	int _a;
};
void FunTest()
{
	B b;
	b.FunTest();  //         FunTest();
	b.A::FunTest();//    A FunTest();
	b._a;             //       
	b.A::_a;         //      
}

代入互換規則
--public
継承
 1.子オブジェクトは親オブジェクトに値を割り当てることができます.
 2.親オブジェクトは子オブジェクトに値を割り当てることができません.
 3.親クラスのポインタ/参照は、子クラスオブジェクトを指すことができます.
 4.子クラスのポインタ/参照は親オブジェクトを指すことはできません(強制タイプ変換で完了できます).
VS 2010では、例えば、
class A
{
public:
	int _a;
};
class B:public A
{
public:
	int _b;
};
void FunTest()
{
	A a;     //    
	B b;     //    
	a=b;
	//b=a;        
	b=*(B*)&a; //       (       )

	A* pa=&b;
	A& ra=b;

	//B* pb=&a;      
	//B& rb=a;       
	B* pb=(B*)&a;  //  
	B& rb=*((B*)&a);
}

四.継承方式
≪単一継承|Single Inheritance|ldap≫:サブクラスが直接親クラスが1つしかない場合、この継承関係を単一継承(単純な基本継承)と呼びます.
≪マルチ継承|Multi Inheritance|emdw≫:1つのサブクラスに2つ以上の直接親があることをマルチ継承と呼びます.
菱形継承:
VS 2010では簡単な例を挙げます.
class A
{
public:
	int _a;
};
class B:public A
{
public:
	int _b;
};
class C:public A
{
public:
	int _c;
};
class D:public B,public C
{
public:
	int _d;
};
void FunTest()
{
	D d;
}
実行監視dオブジェクト構成:
メモリの構成方法は次のとおりです(メモリの分散は継承順)
以上から分かるように、d中_aは2部のメモリ空間を占めて、クラスCとクラスDはすべてクラスAのメンバーを継承したため、菱形の継承は2義性とデータの冗長性の問題が存在して、空間を浪費して、この問題を解決するために、現れます
虚継承:継承方式の前にキーワードを付ける:virtual(_aが1つの空間しか占めず、共有できるようにする)
次のようになります.
class A
{
public:
	int _a;
};
class B:virtual public A
{
public:
	int _b;
};
class C:virtual public A
{
public:
	int _c;
};
class D:public B,public C
{
public:
	int _d;
};
void FunTest()
{
	D d;
	d._a=1;
	d._b=2;
	d._c=3;
	d._d=4;
}

実行完了dメモリの表示:
すなわち、メモリ分布方式は、(すなわち、メモリの第1部と第3部の空間はポインタであり、アドレスを記憶し、このアドレスの内容を監視して表示し、BとC自身に対してそれぞれオフセットアドレスと相対_aオフセットアドレス(これらを1つのテーブルと見なすことができる)を記憶する)
一般的な派生クラスが虚継承の場合、コンパイラはデフォルトの構造関数を合成します.これは、オフセットアドレスを格納するテーブルヘッダアドレスをオブジェクトメモリ格納順序の最初の空間に割り当てます.
ダミー継承は菱形継承の二義性とデータ冗長性の問題を解決するが、ダミー継承効率が低すぎて、テーブルのオフセットアドレスにアクセスするたびにメンバーにアクセスできない.
注意:
1.友元と継承友元の関係は継承できない.つまり、ベースクラスの友元はサブクラスの私有と保護メンバーにアクセスできない.
2.クラスに静的メンバーが含まれている場合、派生クラスの継承数にかかわらず、静的メンバーは1部のみ保存されます.
3.コンストラクション関数とコンストラクション関数は継承できません.