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 源库中所示:

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 回答