c++ - tipos - todas las funciones de arduino
Llamar a una funciĆ³n const desde un objeto no const (11)
Publicado por monjardin
Otra opción sería cambiar el nombre de las funciones anuladas. Esta sería una muy buena idea si las dos funciones realmente tienen diferentes comportamientos / efectos secundarios. De lo contrario, el efecto de la llamada a la función no sería obvio.
IProcess & se accede en otro código principalmente a través de una propiedad
__declspec(property(get=getProcess)) IProcess& Process;
así que renombrarlo no era una opción. La mayoría de las veces la constidad de la función de llamada coincide con getProcess () por lo que no hubo problemas.
Necesito llamar a una función const desde un objeto no const. Ver ejemplo
struct IProcess {
virtual bool doSomeWork() const = 0L;
};
class Foo : public IProcess {
virtual bool doSomeWork() const {
...
}
};
class Bar
{
public:
const IProcess& getProcess() const {return ...;}
IProcess& getProcess() {return ...;}
void doOtherWork {
getProcess().doSomeWork();
}
};
Vocación
getProcess().doSomeWork();
siempre dará como resultado una llamada a
IProcess& getProcess()
¿Hay otra manera de llamar
const IProcess& getProcess() const
de una función miembro no constante? Hasta ahora he usado
const_cast<const Bar*>(this)->getProcess().doSomeWork();
que hace el truco pero parece demasiado complicado.
Editar: Debo mencionar que el código está siendo refactorizado y eventualmente solo quedará una función.
const IProcess& getProcess() const
Sin embargo, actualmente hay un efecto secundario y la llamada const puede devolver una instancia diferente de IProcess algunas veces.
Por favor, sigue con el tema.
Básicamente estás atascado con el cambio de nombre del otro método o const_cast.
Por cierto, esta es una de las razones por las que los punteros inteligentes de copia en escritura en realidad no funcionan bien en C ++. Un puntero inteligente copy-on-write es aquel que se puede compartir infinitamente. Cuando un usuario accede a los datos en un contexto no const, se realiza una copia de los datos (si el usuario no tiene la referencia única). Este tipo de puntero puede ser muy conveniente para usar cuando se comparten estructuras de datos grandes que solo algunos clientes necesitan modificar. La implementación más "lógica" es tener un operador const y un operador sin const->. La versión de const simplemente devuelve la referencia subyacente. La versión no const hace la verificación de referencia única y la copia. No es útil porque un puntero inteligente no const utilizará el operador non-const-> de manera predeterminada, incluso si quisiera usar la versión const. El requisito de const_cast lo hace muy desagradable para el usuario.
Estoy dando la bienvenida a cualquiera que me demuestre que estoy equivocado y muestra un puntero fácil de copiar y copiar en C ++ ...
Bueno, puedes declarar
void doOtherWork const ()
?
Eso lo haría.
Creo que el método const_cast es tu mejor opción. Esto es solo una limitación del marco const en C ++. Creo que la única forma de evitar el casting es definir un método que devuelva la instancia de const IProcess independientemente. Por ejemplo.
const IProcess* getProcessConst() const { return ... }
...
getProcessConst().doSomeWork();
No tiene que hacer ningún truco de lanzamiento si la función no está sobrecargada. Llamar a un método const de un objeto no const está bien. Está llamando a un método no const desde un objeto const que está prohibido. Si los métodos se anulan con una función const y non-const, entonces fundir el objeto en const hará el truco:
const_cast<const IProcess&> (getProcess()).doSomeWork();
EDITAR: No leí toda la pregunta. Sí, necesita const_cast the this puntero o hacer que la función doOtherWork sea const para llamar a const IProcess y getProcess () const .
El punto es que no necesita un objeto const para llamar a doSomeWork . Dado que ese es el objetivo, ¿necesita el método const llamado?
Otra opción sería cambiar el nombre de las funciones anuladas. Esta sería una muy buena idea si las dos funciones realmente tienen diferentes comportamientos / efectos secundarios. De lo contrario, el efecto de la llamada a la función no sería obvio.
Si getProcess()
y getProcess() const
no devuelven una referencia al mismo objeto (pero calificados de forma diferente), entonces indicaría un diseño deficiente de la class Bar
. La sobrecarga en la const
de la función no es una buena forma de distinguir funciones con diferentes comportamientos.
Si están devolviendo una referencia al mismo objeto, entonces:
const_cast<const Bar*>(this)->getProcess().doSomeWork();
y
getProcess().doSomeWork();
llamar exactamente la misma función doSomeWork()
por lo que no es necesario usar el const_cast
.
Supongo que quiere que DoOtherWork llame a una de sus dos llamadas de proceso dependiendo de si se llama desde un objeto const o no.
Lo mejor que puedo sugerir es esto:
class Bar
{
public:
const IProcess& getProcess() const {return ...;}
IProcess& getProcess() {return ...;}
void doOtherWork { // should use getProcess()
getProcess().doSomeWork();
}
void doOtherWork const {
getProcess().doSomeWork(); // should use getProcess() const
}
};
Incluso si eso funciona, esto parece un mal olor para mí. Sería muy cauteloso con el comportamiento de clase que cambia radicalmente según la consistencia de un objeto.
const_cast
es para descartar constness!
Estás emitiendo desde non-const a const que es seguro, así que usa static_cast
:
static_cast<const Bar*>(this)->getProcess().doSomeWork();
Me refiero techincally hablando que puedes lanzar en constness con const_cast
, pero no es un uso pragmático del operador. El objetivo de los nuevos lanzamientos de estilo (en comparación con el antiguo elenco de estilo c) es comunicar el intento del reparto. const_cast
es un olor a código, y su uso debe ser revisado al menos. static_cast
por otro lado es seguro. Pero es una cuestión de estilo C ++.
O puede crear un nuevo método const (privado) y llamarlo desde doOtherWork
:
void doSomeWorkOnProcess() const { getProcess().doSomeWork(); }
Usar un const temporal también es una opción (respuesta por "MSN"):
const Bar* _this = this;
_this->getProcess().doSomeWork();
Si el elenco es demasiado feo para ti, puedes agregar un método a Bar
que simplemente devuelve una referencia constante a *this
:
Bar const& as_const() const {
return *this; // Compiler adds "const" without needing static_cast<>
}
A continuación, puede llamar a cualquier método const
en Bar
simplemente as_const().
, p.ej:
as_const().getProcess().doSomeWork();
Evite el elenco: asígnelo a una const Bar *
o lo que sea y utilícelo para llamar a getProcess()
.
Hay algunas razones pedantes para hacerlo, pero también hace que sea más obvio lo que está haciendo sin forzar al compilador a hacer algo potencialmente inseguro. De acuerdo, es posible que nunca llegue a esos casos, pero también podría escribir algo que no use un molde en este caso.
definir una plantilla
template< class T >
const T & addConst ( T & t )
{
return t;
}
y llama
addConst( getProcess() ).doSomeWork();