No se recomienda el uso de operadores de conversión implícitos. En C++ 11 puede agregar la palabra clave explicit
no solo a constructores de argumento único, sino también a operadores de conversión. Para el código C++ 03, puede usar una función de conversión llamada explícitamente como self()
o down_cast()
.
Además, parece que está utilizando la clase Base
para CRTP, es decir, para habilitar el polimorfismo estático. Eso significa que usted tiene que saber en tiempo de compilación el que una clase particular Derived
que está llamando. Por lo tanto, no debería tener que utilizar las referencias const Base&
en ningún código público, excepto para implementar una interfaz CRTP.
En mis proyectos, que tienen una plantilla de clase enable_crtp
:
#include <type_traits>
#include <boost/static_assert.hpp>
template
<
typename Derived
>
class enable_crtp
{
public:
const Derived& self() const
{
return down_cast(*this);
}
Derived& self()
{
return down_cast(*this);
}
protected:
// disable deletion of Derived* through Base*
// enable deletion of Base* through Derived*
~enable_crtp()
{
// no-op
}
private:
// typedefs
typedef enable_crtp Base;
// cast a Base& to a Derived& (i.e. "down" the class hierarchy)
const Derived& down_cast(const Base& other) const
{
BOOST_STATIC_ASSERT((std::is_base_of<Base, Derived>::value));
return static_cast<const Derived&>(other);
}
// cast a Base& to a Derived& (i.e. "down" the class hierarchy)
Derived& down_cast(Base& other)
{
// write the non-const version in terms of the const version
// Effective C++ 3rd ed., Item 3 (p. 24-25)
return const_cast<Derived&>(down_cast(static_cast<const Base&>(other)));
}
};
Esta clase se deriva de forma privada a partir de ninguna ISomeClass clase base CRTP así:
template<typename Impl>
class ISomeClass
:
private enable_crtp<Impl>
{
public:
// interface to be implemented by derived class Impl
void fun1() const
{
self().do_fun1();
}
void fun2()
{
self().do_fun2()
}
protected:
~ISomeClass()
{}
};
Las diversas clases derivadas pueden aplicar esta interfaz en su propia manera específica de esta manera:
class SomeImpl
:
public ISomeClass<SomeImpl>
{
public:
// structors etc.
private:
// implementation of interface ISomeClass
friend class ISomeClass<SomeImpl>;
void do_fun1() const
{
// whatever
}
void do_fun2()
{
// whatever
}
// data representation
// ...
};
El código externo que llama al fun1
de class SomeImpl
se delegará en la versión const o no const apropiada de self()
en el class enable_crtp
y después de la down_casting se llamará a la implementación do_fun1
. Con un compilador decente, todas las indirecciones deberían optimizarse completamente.
NOTA: los destructores protegidas de ISomeClass
y enable_crtp
hacer el código de seguridad contra los usuarios que tratan de eliminar SomeImpl*
objetos a través de punteros de base.
La sección pertinente sería el de resolución de sobrecarga. –
Si le gustara mi curiosidad, ¿por qué quiere el operador de conversión en 'Base'? –
@ Tony Delroy: 1) para ser menos detallado que llamar explícitamente un method.2 clase) me encontré con este tipo de código de un par de tiempo en la red mientras que intenta conseguir algún conocimiento sobre CRTPs, véase por ejemplo [aquí] (http : //en.wikipedia.org/wiki/Expression_templates) 3) Después de encontrar este comportamiento extraño me puse muy curioso sobre cuál debería ser la correcta :-) – Massimiliano