friends - friend c++>
Hacer un parĂ¡metro de plantilla un amigo? (3)
Ejemplo:
template<class T>
class Base {
public:
Base();
friend class T;
};
Ahora esto no funciona ... ¿Hay alguna manera de hacer esto?
En realidad estoy tratando de hacer un sellador de clases general como este:
class ClassSealer {
private:
friend class Sealed;
ClassSealer() {}
};
class Sealed : private virtual ClassSealer
{
// ...
};
class FailsToDerive : public Sealed
{
// Cannot be instantiated
};
Encontré este ejemplo en este sitio en algún lugar, pero no puedo encontrarlo ... ( here )
Sé que hay otras formas de hacerlo, pero ahora tengo curiosidad si realmente puedes hacer algo como esto.
¿Realmente necesitas hacer esto? Si desea evitar que alguien se derive de su clase, simplemente agregue un comentario y haga que el destructor no sea virtual.
Encontré un truco simple para declarar los parámetros de la plantilla como amigos:
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
Sin embargo, no sé cómo esto podría ayudar a definir una versión alternativa de un sellador de clases.
Está explícitamente prohibido en el estándar, incluso si algunas versiones de VisualStudio lo permiten.
Norma C ++ 7.1.5.3 Especificadores de tipos elaborados, párrafo 2
3.4.4 describe cómo procede la búsqueda de nombres para el identificador en un especificador de tipo elaborado. Si el identificador se resuelve en un nombre de clase o enum-name, el especificador de tipo elaborado lo introduce en la declaración de la misma forma que un especificador de tipo simple introduce su nombre de tipo. Si el identificador se resuelve con un typedef-name o un template tipo-parameter, el especificador de tipo elaborado está mal formado. [Nota: esto implica que, dentro de una plantilla de clase con una plantilla tipo-parámetro T, la clase de amigo de declaración T ; está mal formado. ]
Reconozco el código anterior como un patrón para sellar (no permitir la extensión de) una clase. Hay otra solución, que realmente no bloquea la extensión, pero que indicará que se extiende de forma inadvertida desde la clase. Como se ve en ADOBE Source Library :
namespace adobe { namespace implementation {
template <class T>
class final
{
protected:
final() {}
};
}}
#define ADOBE_FINAL( X ) private virtual adobe::implementation::final<T>
con el uso:
class Sealed : ADOBE_FINAL( Sealed )
{//...
};
Si bien permite la extensión si realmente la fuerza:
class SealBreaker : public Sealed, ADOBE_FINAL( Sealed )
{
public:
SealBreaker() : adobe::implementation::final<Sealed>(), Sealed() {}
};
Restringirá a los usuarios de forma errónea hacerlo.
EDITAR :
El próximo estándar C ++ 11 te permite hacerte amigo de un argumento de tipo con una sintaxis ligeramente diferente:
template <typename T>
class A {
// friend class T; // still incorrect: elaborate type specifier
friend T; // correct: simple specifier, note lack of "class"
};