2011-04-04 12 views
8

Suponiendo que hay una razón legítima para evitar la derivación de alguna clase, Bjarne da una solución here para la respuesta a "¿Puedo detener personas derivadas de mi clase?"Simpler "Prevenir clases derivadas" en C++

Sin embargo, pensé:

class final { 
protected: 
    final() { }   // line 3 
}; 

class B : private virtual final { 
}; 

class D : public B { // line 9 
}; 

int main() { 
    B b; 
    D d;    // line 14 
} 

Cuando intente compilar, se tiene:

foo.cpp: In constructor ‘D::D()’: 
foo.cpp:3: error: ‘final::final()’ is protected 
foo.cpp:9: error: within this context 
foo.cpp: In function ‘int main()’: 
foo.cpp:14: note: synthesized method ‘D::D()’ first required here 

funciona mi solución para todos los casos? En mi humilde opinión, es mejor porque la clase final es genérica y no requiere conocimiento previo de la clase para evitar la derivación.

Respuesta

6

La solución es bastante mala, podría mejorarse con CRTP (Adobe lo hace) pero no será una solución completa. El problema con su código es que otro programador que no quiere romper su contrato (ella es una buena persona) pero no sabe que no debería derivar de su clase podría querer bloquear a otros para que no deriven de su propia clase:

class YourSealedClass : private virtual final {}; 
class HerSealedClass : public YourSealedClass, private virtual final { 
}; 

Tenga en cuenta que ni siquiera hay intención maligna, y el contrato está roto. La mejora obtenida con CRTP sería:

template <typename T> 
class seal 
{ 
protected: 
    seal(){} 
    ~seal(){} 
}; 
class YourSealedClass : private virtual seal<YourSealedClass> {}; 

Esto cogerá el error anterior, como su código sería:

class HerSealedClass : public YourSealedClass, private virtual seal<HerSealedClass> {}; 

Y como ella no es heredera de seal<YourSealedClass> el compilador cogerá para arriba.

El problema con este enfoque es que no bloquea algún programador terco (o maligna) de la escritura:

class MalignClass : public YourSealedClass, private virtual seal<YourSealedClass> {}; 

Para convertirse en un niño de la clase de sellado, y como tal, a tener acceso a su propia clase .

En C++ 0x me creo (tendría que volver a comprobar que) que van a levantar la restricción de que una plantilla no puede hacerse amigo de un parámetro de plantilla, y que será un buen paso en una solución de seguridad de tipos genérico para una clase sellador:

template <typename T> 
class seal { 
    friend class T; // illegal in C++03 
    seal() {}; 
    ~seal() {}; 
}; 
class MySealedClass : private virtual seal<MySealedClass> 
{}; 

la ventaja de este enfoque (actualmente no disponible) es que debido a que el constructor y los destructores son amigos privada sólo puede crear una instancia del tipo. Como está utilizando el CRTP para heredar de una instanciación específica pasando su propio tipo como argumento, le está diciendo al compilador que solo usted puede crear una instancia de su base, y todas las piezas encajan en su lugar.

+0

no todos los constructores son privados de su solución! Te olvidaste de generado automáticamente por el constructor de copia pública del compilador. Hazlo privado también. ¡Uno puede hackear su solución usando el constructor de copia pública del 'sello '! Preparé mi respuesta a una pregunta similar sobre C++ 03: vea http://stackoverflow.com/a/12139218/1463922. – PiotrNycz

2

Probar:

class D : public B, public virtual final 
{ 
}; 
Cuestiones relacionadas