9

デストラクタがパブリックであるのに対し、コンストラクタがプライベートとして宣言されているコードを見てきました。そのような宣言の使用は何ですか?継承中に呼び出しが可能になるように、デストラクタを公開する必要がありますか、それともコードのバグですか?

質問は情報が少し不足しているように見えるかもしれませんが、私が本当に知りたいのは、コンストラクターがプライベートである必要があるときにパブリック デストラクタを使用することが C++ の規則に従うかどうかです。

4

6 に答える 6

9

簡潔な答え

コンストラクタをプライベートとして作成し、デストラクタをパブリックとして作成することには、多くの実用的な用途があります。

このパラダイムを使用して、次のことができます。

長い答え

上記で、プライベート コンストラクターとデストラクターを使用して、いくつかの設計パターンを実装できることをほのめかしました。さて、これが方法です...

参照カウント

オブジェクト内でプライベート デストラクタを使用すると、参照カウント システムに役立ちます。これにより、開発者はオブジェクトの有効期間をより強力に制御できます。

class MyReferenceObject
{
public:
    static MyReferenceObject* Create()
    {
        return new MyReferenceObject();
    }

    void retain()
    {
        m_ref_count++;
    }

    void release()
    {
        m_ref_count--;
        if (m_ref_count <= 0)
        {
            // Perform any resource/sub object cleanup.
            // Delete myself.
            delete this; // Dangerous example but demonstrates the principle.
        }
    }
private:

    int m_ref_count;

    MyReferenceObject()
    {
        m_ref_count = 1;
    }

    ~MyReferenceObject() { }

}

int main()
{
    new MyReferenceObject(); // Illegal.
    MyReferenceObject object; // Illegal, cannot be made on stack as destructor is private.

    MyReferenceObject* object = MyReferenceObject::Create(); // Creates a new instance of 'MyReferenceObject' with reference count.
    object->retain(); // Reference count of 2.
    object->release(); // Reference count of 1.
    object->release(); // Reference count of 0, object deletes itself from the heap.
}

これは、オブジェクトがそれ自体を管理し、開発者がメモリ システムを破壊するのを防ぐ方法を示しています。これはMyReferenceObject自身を削除する危険な例であることに注意してください。これを行う際の考慮事項のリストについては、こちらを参照してください。

シングルトン

シングルトン クラス内のプライベート コンストラクターとデストラクターの主な利点は、コードが設計された方法でのみ使用することをユーザーに強制することです。不正なシングルトン オブジェクトは作成できず (コンパイル時に強制されるため)、ユーザーはシングルトン インスタンスを削除できません (再びコンパイル時に強制されます)。

例えば:

class MySingleton
{
public:
     MySingleton* Instance()
     {
        static MySingleton* instance = NULL;
        if (!instance)
        {
            instance = new MySingleton();
        }

        return instance;
     }
private:
    MySingleton() { }
    ~MySingleton() { } 
}

int main()
{
     new MySingleton(); // Illegal
     delete MySingleton::Instance(); // Illegal.
}

コードが悪用される可能性がほとんどないことを確認してください。の適切な使用はMySingletonコンパイル時に強制されるため、開発者はMySingleton意図したとおりに使用する必要があります。

工場

ファクトリ デザイン パターン内でプライベート コンストラクタを使用することは、ファクトリのみを使用してオブジェクトを作成することを強制する重要なメカニズムです。

例えば:

class MyFactoryObject
{
public:

protected:
    friend class MyFactory; // Allows the object factory to create instances of MyFactoryObject

    MyFactoryObject() {} // Can only be created by itself or a friend class (MyFactory).
}

class MyFactory
{
public:
    static MyFactoryObject* MakeObject()
    {

        // You can perform any MyFactoryObject specific initialisation here and it will carry through to wherever the factory method is invoked.
        return new MyFactoryObject();
    }
}

int main()
{
    new MyFactoryObject(); // Illegal.
    MyFactory::MakeObject(); // Legal, enforces the developer to make MyFactoryObject only through MyFactory.
}

MyFactoryObjectの作成を開発者から隠すため、これは強力です。ファクトリ メソッドを使用して任意の初期化を実行できますMyFactoryObject(例: GUID の設定、DB への登録)。ファクトリ メソッドが使用される場所であればどこでも、その初期化コードも実行されます。

概要

これは、プライベート コンストラクターとデストラクターを使用して API を正しく使用する方法のほんの一例です。トリッキーにしたい場合は、これらすべてのデザイン パターンを組み合わせることもできます ;)

于 2013-08-31T08:43:43.920 に答える
4

まず、デストラクタはプライベートにすることができます。

コンストラクターがプライベートである必要があるときにパブリック デストラクタを持つことは、C++ の規則に従っていますか?

それは完全にC++で動作しています。実際、このシナリオの好例は、コンストラクターがプライベートでデストラクタがパブリックであるシングルトン パターンです。

于 2013-08-31T08:31:09.463 に答える
2

逆順です。

継承中に呼び出しが可能になるように、デストラクタを公開する必要がありますか、それともコードのバグですか?

実際、継承が機能するには、デストラクタは少なくともprotected. デストラクタを持つクラスから継承する場合private、派生クラスに対してデストラクタを生成することはできません。これにより、実際にはインスタンス化が妨げられます (staticメソッドと属性を引き続き使用できます)。

そのような宣言の使用は何ですか?

privateコンストラクターが であっても、クラスには (デフォルトで生成された) パブリック コピー コンストラクターとコピー代入演算子があることに注意してください。このパターンは、次の場合に頻繁に発生します。

  • 名前付きコンストラクタイディオム
  • 工房

名前付きコンストラクタのイディオムの例:

class Angle {
public:
    static Angle FromDegrees(double d);
    static Angle FromRadian(double d);

private:
    Angle(double x): _value(x) {}
    double _value;
};

度またはラジアン (または何でも) で正確に指定する必要があるかどうかはあいまいであるため、コンストラクターが作成され、名前付きメソッドが提供されます。このように使用すると、単位が明確になります。xprivate

Angle a = Angle::FromDegrees(360);
于 2013-08-31T13:43:47.947 に答える
0

私の頭の中の 1 つの例として、クラス インスタンス番号を 0 または 1 に制限したいとします。たとえば、一部のシングルトン クラスでは、アプリケーションがオブジェクトを一時的に破棄してメモリ使用量を減らすことができるようにする必要があります。このコンストラクタを実装するにはプライベートになりますが、デストラクタはパブリックになります。次のコード スニペットを参照してください。

class SingletoneBigMemoryConsumer
{
private:
    SingletoneBigMemoryConsumer()
    {
        // Allocate a lot of resource here.
    }

public:
    static SingletoneBigMemoryConsumer* getInstance()
    { 
        if (instance != NULL) 
            return instance;
        else
            return new SingletoneBigMemoryConsumer();
    }
    ~SingletoneBigMemoryConsumer()
    {
        // release the allocated resource.
        instance = NULL;
    }
private:
    // data memeber.
    static SingletoneBigMemoryConsumer* instance;
}



//Usage.
SingletoneBigMemoryConsumer* obj = SingletoneBigMemoryConsumer::getInstance();
// You cannot create more SingletoneBigMemoryConsumer here.
// After 1 seconds usage, delete it to reduce memory usage.
delete obj;
// You can create an new one when needed later
于 2013-08-31T08:53:08.520 に答える