47

例:

template<class T>
class Base {
public:
    Base();
    friend class T;
};

これは機能しません...これを行う方法はありますか?

私は実際にこのような一般的なクラスのシーラーを作ろうとしています:

class ClassSealer {
private:
   friend class Sealed;
   ClassSealer() {}
};
class Sealed : private virtual ClassSealer
{ 
   // ...
};
class FailsToDerive : public Sealed
{
   // Cannot be instantiated
};

このサイトのどこかでこの例を見つけましたが、見つかりません... (ここ)

これを行う他の方法があることは知っていますが、実際にこのようなことができるかどうか知りたいです。

4

3 に答える 3

48

VisualStudio の一部のバージョンで許可されていても、標準では明示的に禁止されています。

C++ 標準 7.1.5.3 詳細な型指定子、段落 2

3.4.4 では、詳細型指定子の識別子の名前検索がどのように進行するかについて説明します。識別子がクラス名または列挙名に解決される場合、単純型指定子がその型名を導入するのと同じ方法で、詳細型指定子はそれを宣言に導入します。識別子が typedef-name またはテンプレートの型パラメーターに解決される場合、詳細な型指定子の形式が正しくありません。[注: これは、テンプレート型パラメーター T を持つクラス テンプレート内で、宣言 のフレンド クラス Tを意味します。は不正です。]

上記のコードは、クラスを封印する (拡張を禁止する) パターンとして認識しています。拡張機能を実際にブロックするのではなく、クラスから誤って拡張することを示す別の解決策があります。ADOBE Source Libraryに見られるように:

namespace adobe { namespace implementation {
template <class T>
class final
{
protected:
   final() {}
};
}}
#define ADOBE_FINAL( X ) private virtual adobe::implementation::final<T>

使用法で:

class Sealed : ADOBE_FINAL( Sealed )
{//...
};

あなたが本当にそれを強制した場合、それは拡張を許可しますが:

class SealBreaker : public Sealed, ADOBE_FINAL( Sealed )
{
public:
   SealBreaker() : adobe::implementation::final<Sealed>(), Sealed() {}
};

ユーザーが誤ってそれを行うのを制限します。

編集

次の C++11 標準では、わずかに異なる構文で型引数と友達になることができます。

template <typename T>
class A {
   // friend class T; // still incorrect: elaborate type specifier
   friend T;          // correct: simple specifier, note lack of "class"
};
于 2009-03-31T19:35:43.820 に答える
22

テンプレート パラメーターをフレンドとして宣言するための簡単なトリックを見つけました。

template < typename T>
struct type_wrapper 
{ 
   typedef T type; 
}; 


template < typename T> class foo 
{ 
  friend class type_wrapper < T>::type 
};   // type_wrapper< T>::type == T

ただし、これがクラス シーラーの代替バージョンを定義するのにどのように役立つかはわかりません。

于 2011-04-09T23:04:48.823 に答える
2

本当にこれを行う必要がありますか? 誰かがあなたのクラスから派生するのを防ぎたい場合は、コメントを追加してデストラクタを非仮想にします。

于 2009-03-31T19:30:22.617 に答える