C++で特殊なクラスを作成する方法を教えます


言語について言えば、個人はやはりC++が好きで、C++のいくつかの文法の方面は確かに比較的に奥深いが、これらは確かに実際の応用の中で取って代わることができない位置を遮ることができません.
今日のポイントは、特殊なC++クラスをどのように定義するかについて話します.
1、継承できないC++クラスを定義する
どのようにしてクラスを継承できませんか?簡単に言えば、私たちが達成したい効果は、このクラスを継承すれば、コンパイルが直接エラーを報告することです.
このクラスを実現するには、以下のC++の簡単な文法を事前に理解してほしい:友元クラス、虚継承.ここでは、どのように定義するかを直接教えてあげます.次に、なぜかについて議論します.
ステップ1:空のクラスAを定義し、構造とプロファイルを明示的に与え、構造とプロファイルをprivateとして定義する必要があります.
ステップ2:継承できないクラスBを定義し、正常な構造と解析を与え、publicタイプを与え、BにAクラスを虚に継承させ、継承方式を制限せず、同時にBをAの友元クラスに設定する.
ステップ3:クラスCを定義して仮想継承クラスBを試み、コンパイルエラー! 
コードは次のとおりです.
class A
{
	friend class B;
private:
	A(){}
	~A(){}
};

class B:virtual public A
{
public:
	B()
	{}
};

class C :public B
{
public:
	C()
	{}
};

なぜコンパイルが間違っているのかについてお話しします.
まずクラスAのコンストラクション関数とコンストラクション関数をプライベートとして定義し、定義が表示されない場合はデフォルトのコンストラクション関数とコンストラクション関数はpublicです.ではprotectedタイプとして定義してもいいですか?答えは「NO」です.継承を理解すると、ベースクラスのprivateタイプのメンバー変数またはメソッドは、すべての派生クラスでは表示されませんが、protectedタイプのメンバー変数またはメソッドが表示されていることがわかります.我々の目的は,後でクラスAの派生クラスを構築する場合,クラスAの構造を呼び出す必要があり,このメソッドをクラスAの内部で呼び出さなければならないことである.派生クラスであっても,派生クラスには見えないという遵守を望んでいる.
次に、クラスBはクラスAを継承し、継承方式はどうでもいい.ベースクラスのプライベート部分はどのように継承しても見えないからだ.どうして虚継承するの?これは後で話します.同時に、クラスBはここでクラスAの友元クラスとして定義され、その後、クラスBはクラスAのプライベートメンバーに直接アクセスすることができ、すなわち、ここの友元は、私たちが最初に定義した派生クラスに見えない制限を破った.その後,クラスBを用いてオブジェクトをインスタンス化する際には完全に成功し,ベースクラス部分を構築することは,継承方式とは無関係に友元によって実現される.ここでのクラスBは,我々が定義した継承できないクラスである.
最後に,クラスCにクラスBを継承させてみると,クラスCがオブジェクトをインスタンス化する(あるいは構造関数を明示的に定義する)と,まずクラスBに属する部分を構築する.ここで,クラスBがダミー継承クラスAでなければ,ここでクラスBに属する部分を構築する場合,クラスBによってクラスA部分を構築することは必然的に成功する.しかし,我々は望んでいないので,ここでクラスB虚がクラスAを継承し,構造がクラスB部分に属する場合,B虚がAを継承するとクラスCから直接Aにアクセスし,クラスAの部分を構築しようとするが,明らかにクラスAの構造関数にアクセスできないため,Cインスタンス化対象は失敗する.その後、クラスBを継承しようとするすべてのクラスは、コンパイル時に失敗します(Cに構造が示されているか、クラスCにオブジェクトがインスタンス化されていることが前提です).
ここまで,クラスBの作成に成功したことを継承することはできないが,ここでは友元クラスの概念を巧みに適用し,BのみがAに属する部分をインスタンス化できることを実現した.
この方法が柔軟すぎて理解しにくいと思ったら、もっと簡単な方法があります.C++11はfinalキーワードを導入し,そのキーワードで修飾されたクラスは継承できないが,javaでの用法とほぼ一致している.
class A final
{
public:
	A(){}
};

class B :public A        //     
{};

2、スタック上でのみオブジェクトを作成できるクラスを定義する
上記のような状況が理解できれば、ここはあまり難しくないはずです.スタックにオブジェクトのみを作成できるのはなぜですか?どのように実現しますか?スタック上でオブジェクトを作成できるインタフェースだけを外部に露出すれば簡単です.コードは次のとおりです.
class A
{
public:
	static A* Get_A(int x)
	{
		return new A(x);
	}
	static void Delete_A(A* a)
	{
		delete a;
	}
private:
	A(int a = 10)
		:_a(a)
	{}
private:
	int _a;
};

int main()
{
	A* pa = A::Get_A(9);
	A* pb = A::Get_A(7);
	return 0;
}

以前と同様に、コンストラクション関数とコンストラクション関数をプライベートに設定します(ここでは継承に関与しないため、privateとprotectedはここで区別されません).コンストラクション関数はすべてプライベートであり、オブジェクトを作成できないため、newとdeleteによってスタック上のオブジェクトの取得と解放を実現する静的な方法が提供されます.
3、スタック上でのみオブジェクトを作成できるクラスを定義する
前を理解すれば、ここでどうすればいいかを知るべきだ.スタック上でオブジェクトを取得する方法だけを提供すればいいです.スタック空間はオペレーティングシステムによって維持されているため、特別な必要はありません.構造関数は明示的に与える必要はありません.コードは以下の通りです.
class A
{
public:
	static A Get_A(int x)
	{
		return A(x);
	}
private:
	A(int a = 10)
		:_a(a)
	{}
private:
	int _a;
};

int main()
{
	A pa = A::Get_A(9);
	A pb = A::Get_A(7);
	return 0;
}

スタック上またはスタック上でしか作成できないオブジェクトは、実装原理は同じであり、クラスの構造と構造関数はすべてプライベートに設定されており、私のインタフェース関数が提供する方法がスタックから作成されたオブジェクトである場合、クラスはスタック上でしか作成できません.私のインタフェース関数がスタックから直接得られるオブジェクトを提供する場合、クラスはスタック上でのみオブジェクトを作成できます.スタック上のオブジェクトを作成するときに、一時的なオブジェクトの参照を返すことはできません.これはあまり説明されません.
------muhuizz整理