2011-12-19 5 views
9

Tengo una clase de C++ que implementa el recuento de referencias y quiero que todos los usuarios de esta clase hereden de esta clase solo virtualmente para que ningún objeto termine con más de un contador de referencia.¿Cómo detectar y afirmar la herencia virtual para una clase específica?

Me gustaría alguna forma de afirmar este requerimiento ya sea durante el tiempo de compilación o al menos durante el tiempo de ejecución.

¿Hay alguna manera de lograr eso?

Respuesta

5

Creo que envolver la clase sería la opción más simple. En lugar de heredar directamente de RefCounter, crea una clase intermedia.

struct RefCounterVirtPrivate_ 
{ 
    int count; 

    RefCounterVirt() 
     : count(0) 
    { } 
}; 

struct RefCounter : public virtual RefCounterVirtPrivate_ 
{ 
}; 

struct A : public RefCounter { }; 
struct B : public RefCounter { }; 
struct C : public A, public B { }; 

Luego todo se puede heredar de RefCounter sin ninguna necesidad de preocuparse por inheritence virtual. Ni siquiera tiene que cambiar ningún código existente; la herencia virtual de RefCounter en sí misma debería ser inofensiva.

Esto, por supuesto, no garantiza que las personas no hereden de RefCounterVirtPrivate_ directamente, pero es por eso que le he dado un nombre obvio. Es más difícil hacer esto accidentalmente que olvidar una palabra clave virtual.

0

Debería ser posible con algunos trucos, pero tenga en cuenta las implicaciones: está estableciendo la política que el objeto necesita para autodestruirse inmediatamente si su contador de referencia llega a cero.

Dependiendo de la aplicación, es posible que desee dejar el momento exacto en que llama delete this; a la implementación del objeto, es decir, sólo tiene add_ref() y release() funciones abstractas en la clase base (lo que hace que la aplicación concreta aparece en todos los vtables de interfaz con thunk apropiado) y colocan la carga de mantener el recuento de referencias en la clase concreta.

+0

En realidad, esta clase sí 'delete this' en todo momento, por lo que podría hacer las comprobaciones en' addref() '/' release() '. Entonces el engaño es bienvenido. – sharptooth

9

¿Algo como esto?

struct RefCounter { 
    template <typename T> 
    RefCounter(T *) { 
     BOOST_STATIC_ASSERT(boost::is_virtual_base_of<RefCounter, T>); 
    } 
}; 

struct GoodClass : virtual RefCounter { 
    GoodClass() : RefCounter(this) {} 
}; 

struct BadClass : RefCounter { 
    BadClass() : RefCounter(this) {} 
}; 

Es una pena por tener que pasar this al constructor, sin embargo, para capturar el tipo derivado. Y, por supuesto, un usuario intencionalmente obtuso podría subvertirlo pasando algo que no sea this.

+0

Puede usar CRTP en lugar de 'esto', pero creo que su solución es mejor. – sbi

+0

@sbi: lo consideré, pero luego 'RefCounter ' y 'RefCounter ' serían clases diferentes, por lo que incluso si son virtuales, podría terminar con múltiples subobjetos de clase base de refcounter. –

+0

¿Esto funcionará si una clase hereda de dos bases y una base hereda del 'RefCounter' virtualmente y la otra hereda de manera no virtual? – sharptooth

Cuestiones relacionadas