18

「Base」というクラスと、Base のサブクラスで保護されたメソッドと Base のメンバーにアクセスする「Derived」というクラスがあるとします。

私が今やりたいことは、他のクラスが Derived をサブクラス化できないようにすることです。Java では、Derived クラスを「final」と宣言することでそれを実現できます。同じ効果が得られる C++ のトリックはありますか?

(理想的には、Derived 以外のクラスが Base をサブクラス化できないようにしたいと考えています。Base と Derived は両方ともテンプレート化されているため、すべてのコードを同じクラスに入れたり、friend キーワードを使用したりすることはできません。 Derived よりもテンプレート引数が少ないベース....)

4

5 に答える 5

15

C++11 では、final キーワード (実際にはキーワードではないため、技術的には特別な識別子) をクラスに追加できます。

class Derived final
{
...

final キーワードの詳細については、http://en.wikipedia.org/wiki/C++11#Explicit_overrides_and_finalを参照してください。

于 2012-09-07T13:58:42.177 に答える
9

' ' のプライベート コンストラクターDerivedと、インスタンス化のための public static Create 関数を使用できます。

于 2009-08-07T21:39:40.973 に答える
6

サブクラス化を禁止する最も簡単な方法は、コンストラクターを非公開にすることです。

class Foo
{
private:
    Foo() {}

public:
    static Foo* CreateFoo() { return new Foo; }
};

編集:これには静的なFactoryメソッドが必要であることを指摘してくれたIndeeraに感謝します

于 2009-08-07T21:40:22.737 に答える
3

それを行う簡単でクリーンな方法はありません。

標準ライブラリが行うことは、単純にデストラクタを非仮想にすることです。これはサブクラス化を妨げるものではありませんが、継承用に設計されていないことをユーザーに強く知らせるものであり、派生クラスを使用するときは非常に注意する必要があることを意味します。

最終的には、サブクラス化を絶対に不可能にする必要がありますか? 「このクラスから派生するのは悪い考えだ」ということを示すのに十分ではありませんか?

本当に望むなら、人々はいつでもあなたのコードを壊すことができます。あなたができる最善のことは、彼らがすべきこととすべきでないことを彼らに認識させ、彼らがあなたのコードを積極的に壊そうとしないことを願うことです.

コードをマキャベリではなく、マーフィーから保護してください。;)

于 2009-08-07T22:30:30.093 に答える
1

テンプレートを使用しているので、Derived 以外のクラスを Base からサブクラスにできないようにすることに関する質問の最後の部分は、適切な部分的な特殊化を使用して行うことができると考えていました。

次のコード スニペットは私が思いついたものですが、必要な複雑さは jalf による答えを強化するだけです。その価値はありますか?どちらかといえば、これは、実際に使用するテクニックを解決するよりも、部分的な専門化を理解するのに役立ちました.

COMMON を使用して、Base と Derived の間で共有されるテンプレート パラメーターを示し、EXTRA を使用して、Derived が持っていると言う追加のパラメーターを示します。これらの実際の数は、たまたまそれぞれ 1 つと 2 つを選んだだけです。

// Forward declaration of class Derived
template< class COMMON
        , class EXTRA1
        , class EXTRA2 >
class Derived;


// Definition of general class template Base
template< class SUBCLASS
        , class COMMON >
class Base
{
private:
    Base() {}
};


// Definition of partial specialisation of template class Base to open up
// access to the constructor through friend declaration.
template< class COMMON
        , class EXTRA1
        , class EXTRA2 >
class Base< Derived< COMMON, EXTRA1, EXTRA2 >
          , COMMON >
{
private:
    Base() {}

    friend class Derived< COMMON, EXTRA1, EXTRA2 >;
};


// Definition of class Derived
template < class COMMON
         , class EXTRA1
         , class EXTRA2 >
class Derived
    : public Base< Derived< COMMON, EXTRA1, EXTRA2 >
                 , COMMON >
{
public:
    static Derived* create() { return new Derived; }

private:
    Derived() : Base< Derived< COMMON, EXTRA1, EXTRA2 >
                    , COMMON >()
    {
    }
};


// Definition of class HonestDerived.
// It supplies itself as the SUBCLASS parameter to Base.
template < class COMMON
         , class EXTRA1
         , class EXTRA2 >
class HonestDerived
    : public Base< HonestDerived< COMMON, EXTRA1, EXTRA2 >
                 , COMMON >
{
public:
    HonestDerived() : Base< HonestDerived< COMMON, EXTRA1, EXTRA2 >
                          , COMMON >()
    {
    }
};


// Definition of class DishonestDerived
// It supplies Derived rather than itself as the SUBCLASS parameter to Base.
template < class COMMON
         , class EXTRA1
         , class EXTRA2 >
class DishonestDerived
    : public Base< Derived< COMMON, EXTRA1, EXTRA2 >
                 , COMMON >
{
public:
    DishonestDerived() : Base< Derived< COMMON, EXTRA1, EXTRA2 >
                             , COMMON >()
    {
    }
};


template< class COMMON, class EXTRA1, class EXTRA2 >
class DerivedFromDerived
    : public Derived< COMMON, EXTRA1, EXTRA2 >
{
public:
    DerivedFromDerived() : Derived< COMMON, EXTRA1, EXTRA2 >()
    {
    }
};

// Test partial specialisation gives Derived access to the Base constructor
Derived< int, float, double >* derived
    = Derived< int, float, double >::create();

// Test that there is no access to the Base constructor for an honest subclass
// i.e. this gives a compiler error
HonestDerived< int, float, double > honestDerived;

// Test that there is no access to the Base constructor for a dishonest subclass
// i.e. this gives a compiler error
DishonestDerived< int, float, double > dishonestDerived;

// Test that there is no access to the Derived constructor
// i.e. this gives a compiler error
DerivedFromDerived< int, float, double > derivedFromDerived;

このコードは gcc 4.3.2 でテストされています。

フレンド宣言の代わりに、Base の部分的な特殊化でコンストラクターを保護することもできますが、それによって DishonestDerived のようなクラスが動作できるようになることに注意してください。

于 2009-08-08T10:45:52.783 に答える