[C++]——特別なクラス設計

目次

序文

(1) コピーできないクラスを設計する

(2) ヒープ上にのみオブジェクトを作成できるクラスを設計する

(3) スタック上にのみオブジェクトを作成できるクラスを設計する

(4) 継承できないクラスを設計する

要約する


序文

特別なクラスの設計とは、オブジェクト指向プログラミングにおける特定のニーズや状況に応じて、特別な機能や属性を持つクラスを作成することを指します。特別なクラスは、特定の問題を解決したり、特別なニーズを満たすように設計されており、コードをより柔軟で拡張可能にします。


(1) コピーできないクラスを設計する

コピーは、コピー コンストラクターと代入演算子のオーバーロードの 2 つのシナリオでのみ発生します。したがって、クラスによるコピーを防止する場合は、クラスがコピー コンストラクターと代入演算子のオーバーロードを呼び出すことを防止するだけで済みます

次に、C++98 と C++11 の 2 つのシナリオから 2 つがどのように実装されるかを見てみましょう。

[C++98]:コピー コンストラクターと代入演算子のオーバーロードは、それが定義されていないことを宣言するだけであり、そのアクセス権はプライベートに設定されます。

  •  コードは以下のように表示されます。
class CopyBan
{
private:
	CopyBan(const CopyBan&); // 声明拷贝构造函数为私有
	CopyBan& operator=(const CopyBan&); // 声明拷贝赋值运算符为私有

public:
	CopyBan() {} // 默认构造函数
};

【説明する】

  1. private に設定する:ステートメントのみが private に設定されていない場合、ユーザーがクラス外で定義した場合、コピーを禁止できません
  2. 宣言するだけで定義しない:関数が全く呼び出されないので定義しない、定義しても意味がない、書かないほうが簡単、定義しても防げないメンバー関数の内部コピー。
     

このクラスを使用する場合は、単にそれを継承します。

class MyClass : public CopyBan{
    // 类的定义
};

[C++11]: C++11 では、delete の使用法が拡張されており、new によって要求されたリソースを解放することに加えて、delete の後に =delete が続く場合、コンパイラがデフォルトのメンバー関数を削除することを意味します。

  • コードは以下のように表示されます。
class CopyBan
{
	//.....

	CopyBan(const CopyBan&) = delete;			// 删除拷贝构造函数
	CopyBan& operator=(const CopyBan&) = delete; // 删除拷贝赋值运算符

	//.....
};

【説明する】

  1. 上の例では、CopyBanというクラスを定義しました。コピー コンストラクターとコピー代入演算子を delete として宣言することで、オブジェクトのコピー機能を無効にします。
  2. このように、CopyBan型のオブジェクトをコピーしようとすると、コンパイル時にエラーが発生します。

 

同じクラスを使用する場合は、単純にそれを継承します。

class MyClass : public CopyBan{
    // 类的定义
};
  • この例では、MyClass は  CopyBan クラスを継承します。ただし、基本クラス CopyBan はコピー コンストラクターと代入演算子の関数を無効にするため、MyClass では コピー操作を実行できません。

【まとめ】

  • この設計を使用すると、クラスのインスタンスが決してコピーされないようにできるため、不必要なオブジェクトの重複や発生する可能性のあるエラーを回避できます。


(2) ヒープ上にのみオブジェクトを作成できるクラスを設計する

実現方法:

  • クラスのコンストラクターをプライベートにし、コピー コンストラクターをプライベートとして宣言します。他のユーザーが copy を呼び出してスタック上にオブジェクトを生成できないようにします。
  •  静的メンバー関数を提供し、静的メンバー関数でヒープ オブジェクトの作成を完了します。

【C++98】 :

  • コードは以下のように表示されます。
class HeapOnly
{
public:
	static HeapOnly* CreateObject()
	{
		return new HeapOnly();
	}
private:
	HeapOnly() {}		// 私有化默认构造函数
	// C++98
	// 1.只声明,不实现。因为实现可能会很麻烦,而你本身不需要
	// 2.声明成私有
	HeapOnly(const HeapOnly&);
};

【C++11】:

  • コードは以下のように表示されます。
class HeapOnly
{
public:
	static HeapOnly* CreateObject()
	{
		return new HeapOnly();
	}
private:
	HeapOnly() {}		// 私有化默认构造函数

	// C++11
	HeapOnly(const HeapOnly&) = delete;
};

 【説明する】

  1. C++11 標準以降、= deleteコピー コンストラクターは、プライベートを宣言するだけでなく、 を使用して削除できます。
  2. このアプローチはより明確で、コードがより読みやすく、表現力豊かになります。したがって、このような要件を実現するには、C++11 以降の標準を使用することをお勧めします。

このように、次のコードを使用して、ヒープ上に HeapOnly クラス オブジェクトを作成できます。 

HeapOnly* obj = HeapOnly::CreateObject();

オブジェクトの使用が終了したら、必ず呼び出して手動でメモリを解放してください delete 。

delete obj;

 

【まとめ】

  • このように設計されたクラスは、ヒープ上にのみオブジェクトを作成でき、コピーや代入によって新しいオブジェクトを作成できないため、オブジェクトの一意性と作成方法の制約が保証されます。

(3) スタック上にのみオブジェクトを作成できるクラスを設計する

実装:

  • スタック上にオブジェクトのみを作成できるクラスを設計するには、プライベート デストラクターとパブリックの静的メンバー関数を使用できます。

【C++98】 :

  • コードは以下のように表示されます。
class StackOnly 
{
public:
    static StackOnly CreateObj() {
        return StackOnly();
    }

private:
    StackOnly() {} // 私有化默认构造函数
    ~StackOnly() {} // 私有化析构函数
};

【説明する】

  1. 上の例では、デフォルトのコンストラクターとデストラクターをプライベートにしました。これは、StackOnly クラスのオブジェクトを外部から直接インスタンス化または破棄できないことを意味します。
  2. オブジェクトを作成できるようにするために、CreateObj と呼ばれるパブリック静的メンバー関数を提供します。この関数は、StackOnly 型のオブジェクトを返します。

コード例を使用します。

StackOnly obj = StackOnly::CreateObj();
  •  これにより、プライベートのデフォルト コンストラクターには直接アクセスできないため、StackOnly クラスのオブジェクトはスタック上にのみ作成できるようになります。
  • オブジェクトの破棄はコンパイラによって自動的に処理されます(メモリを解放するために手動で呼び出す必要はありませんdelete)。オブジェクトがスコープ外になると、リソースを解放するためにデストラクタが自動的に呼び出されます。

[C++11]:特殊なメンバー関数を削除し、new 演算子と delete 演算子の使用を防止することで、スタック上にオブジェクトのみを作成できるクラスを実装できます。

  • コードは以下のように表示されます。
class StackOnly
{
public:
    StackOnly() = default; // 允许默认构造函数

    // 删除拷贝构造函数和赋值运算符函数
    StackOnly(const StackOnly&) = delete;
    StackOnly& operator=(const StackOnly&) = delete;

    // 禁止使用new和delete操作符
    void* operator new(size_t) = delete;
    void operator delete(void*) = delete;
};

コード例を使用します。

StackOnly obj1; // 在栈上创建对象

// 下面的代码将导致编译错误,因为拷贝构造函数被删除
// StackOnly obj2 = obj1;

// 下面的代码将导致编译错误,因为赋值运算符函数被删除
// StackOnly obj3;
// obj3 = obj1;

// 下面的代码将导致编译错误,因为使用了删除的new运算符
// StackOnly* ptr = new StackOnly;

// 下面的代码将导致编译错误,因为使用了删除的delete运算符
// delete ptr;

【説明する】

  • このように設計されたクラスは、オブジェクトをスタック上に作成することしかできず、値をコピーしたり代入したりして新しいオブジェクトを作成することはできず、同時にオブジェクトのメモリの使用や割り当て、解放も禁止されているため、オブジェクトの一意性が保証されnewますdelete。オブジェクトと作成方法の制限。

上記のメソッドに加えて、スタック上にオブジェクトのみを作成できるクラスを実装するために使用できるかなり独特な方法があります。これは、コンストラクターとデストラクターを削除せずにプライベートoperator newおよび関数を定義することによってoperator delete実現されます

  • コードは以下のように表示されます。
class StackOnly 
{
public:
    // 在 public 区域声明 operator new 和 operator delete 函数
    static void* operator new(size_t size) = delete; // 删除 operator new 函数
    static void operator delete(void* ptr) noexcept = delete; // 删除 operator delete 函数

private:
    // 私有化所有构造、析构函数,包括默认构造函数
    StackOnly() {}
    StackOnly(const StackOnly&) {}
    ~StackOnly() {}
};

【説明する】

  1. 上の例では、コンストラクターとデストラクターの両方をプライベートにすると、ヒープ上でオブジェクトが作成または破棄されなくなります。同時に、ヒープ上のメモリの割り当てとメモリの解放に使用される、削除された演算子 new 関数と演算子削除関数をパブリック領域で宣言しました。
  2. このクラスの演算子 new 関数と演算子削除関数はデフォルトで public であるため、再定義する必要があります。これを削除として宣言すると、ヒープ上で直接メモリを割り当てたり解放したりすることが完全に禁止されるため、ヒープ上にオブジェクトが作成されなくなります。

 このクラスを使用する場合、操作はスタック上のオブジェクトを通じてのみ実行できます。

StackOnly obj;

【知らせ】

  • StackOnlyクラスのオブジェクトがスタック上にのみ作成できるようにします。ただし、このメソッドの注意点は、演算子 new 関数や演算子削除関数を使用する必要があるため、場合によってはコンパイルできない場合があるため、使用する場合は注意が必要です。


(4) 継承できないクラスを設計する

実装:

  • C++98 標準を使用する場合、コンストラクターとデストラクターをプライベートにし、パブリックの静的ファクトリ メソッドを提供しないことにより、継承できないクラスを実装できます。

【C++98】 :

  • コードは以下のように表示されます。
class NonInherit
{
private:
    NonInherit() {}
    ~NonInherit() {}

public:
    // 禁止通过静态工厂方法创建对象
    static NonInherit* GetInstance() {
        return NULL;
    }
};

実装:

  • C++11 以降の標準では、クラス宣言の最後にキーワードを追加して、finalクラスが継承不可能であることを明示的に示すことができます。

【C++11】:

  • コードは以下のように表示されます。
class A final
{
    // ....
};

【説明する】

  1. 上記の例では、クラスの定義の前に Final キーワードを使用して、A を最終クラスとして宣言しました。これは、他のクラスが A から継承できないことを意味します。
  2. 他のクラスが A から継承しようとすると、コンパイラはエラーを報告します。

 例えば:

class A final 
{
	//...
};

class B : public A { // 编译错误
	// 类定义
};

エラーは次のとおりです。 


要約する

これらの特別なクラスの設計目的は、特定のニーズとプログラミング シナリオに基づいて決定されます。

これらは、コードの編成、保守性、拡張性、再利用性に役立ちます。これらの特別なクラスを適切に設計して使用することにより、コードの品質、読みやすさ、信頼性を向上させることができます。

以上で、今回の特殊クラス設計の説明は終了です。見てくださった皆様、応援してくださった皆様、ありがとうございました!

 

おすすめ

転載: blog.csdn.net/m0_56069910/article/details/132723051