2010-10-28 17 views
10

Me gustaría saber si es posible llamar a una función de miembro no const desde una función de miembro constante. En el ejemplo siguiente Primero da un error de compilación. Entiendo por qué da un error, me gustaría saber si hay una forma de evitarlo.Llamar a una función de miembro no const desde una función de miembro constante

class Foo 
{ 
    const int& First() const 
    { 
     return Second(); 
    } 

    int& Second() 
    { 
     return m_bar; 
    } 

    int m_bar; 
} 

Realmente no quiero hablar de la sabiduría de hacer esto, tengo curiosidad si es posible.

+3

Usted no es el primero: http://stackoverflow.com/questions/856542/elegant-solution-to-duplicate-const-and-non-const-getters –

+0

gracias Hasta que, no apareció en mi búsqueda – Steve

Respuesta

28
return (const_cast<Foo*>(this))->Second(); 

Entonces llora, en voz baja.

+0

¿Qué ocurre si las funciones tienen el mismo nombre? const int y GetBar() const; int & GetBar(); – phandinhlan

+0

Puede sobrecargar una función en constness, por lo que simplemente funcionará. – user3063349

10

Es posible :

const int& First() const 
{ 
    return const_cast<Foo*>(this)->Second(); 
} 

int& Second() { return m_bar; } 

Yo no recomendaría este; es feo y peligroso (cualquier uso de const_cast es peligroso).

Es mejor mover tanta funcionalidad común como sea posible a las funciones de ayuda, luego haga que las funciones de miembro const y no const hagan cada una de ellas el mínimo trabajo que necesiten.

En el caso de un acceso simple como este, es tan fácil para return m_bar; de ambas funciones como para llamar a una función desde la otra.

+0

O simplemente gire 'int & Second()' en 'int & Second() const'. Las funciones miembro non-'const' no tendrán problemas para llamar a 'Second()', pero ahora las funciones miembro 'const' también podrán llamarlo sin ningún tipo de jiggery-pokery. –

+0

@Jeremy: ¿Cómo supongo que devolvemos una referencia no const a un miembro, entonces? – GManNickG

+0

@GMan: Touché. No se puede sin declarar 'm_bar' como' mutable int'. La recomendación de @Fred Larson es bastante buena, pero la dirección a la que conduce: escribir dos accesos benditos dos veces, una vez que 'const' se modificó y otra vez no, no es tan alegre. –

3

Por la definición de const, una función no debe modificar el estado de un objeto. Pero si llama a otro miembro no const, el estado del objeto puede cambiarse, por lo que no se permite.

Sé que dijiste que no querías saber sobre esto, pero creo que es importante para otros que suceda con la pregunta.

2

Sobrecarga en const:

const int& Second() const 
{ 
    return m_bar; 
} 

puede agregar a este método y mantener la versión original no constante.

1

iteradores son similares en esto y hacen un estudio interesante.

iteradores de const son a menudo la base para iteradores 'no const', y a menudo encontrará const_cast<>() o modelos de estilo C utilizados para descartar const de la clase base con accesos en el niño.

Editar: comentario fue

Tengo un iterador postal del lugar donde la const hereda de la no-const

Este sería en general la estructura inheritence mal (si su decir lo que creo que lo es), la razón es que los niños no deberían ser menos restrictivos que los padres.

dice que tiene algún algoritmo tomando su iterador zip, ¿sería apropiado pasar un iterador de const a un const no?

si tiene un contenedor const, solo podría pedirle un iterador de const, pero luego el const iterator se deriva de un iterador por lo que solo debe usar las funciones en el padre para tener acceso no const.

Aquí es un esquema rápido de sucesiones sugerido siguiendo el modelo STL tradicional

class ConstIterator: 
    public std::_Bidit< myType, int, const myType *, const mType & > 
{ 
    reference operator*() const { return m_p; } 
} 

class Iterator : public ConstIterator 
{ 
    typedef ConstIterator _Mybase; 
    // overide the types provided by ConstIterator 
    typedef myType * pointer; 
    typedef myType & reference; 

    reference operator*() const 
    { 
    return ((reference)**(_Mybase *)this); 
    } 
} 

typedef std::reverse_iterator<ConstIterator> ConstReverseIterator; 
typedef std::reverse_iterator<Iterator> ReverseIterator; 
+0

Tiendo a escribir iteradores como clases de plantilla y uso rasgos de tipo para manipular la constness de las funciones de miembro; evita la necesidad de 'const_cast' y hace que el código sea más fácil de leer. –

+0

Suena interesante, aunque ¿permite el uso de iteradores donde puede usar const_iterator? Estoy haciendo esta observación original en el stl (s) que he visto, que es principalmente a los que tienen MSVC. –

+0

esto fue en realidad mi caso de uso para esto. Tengo un iterador zip donde el const hereda de non-const. @James, ¿podría responder esta pregunta con la respuesta de rasgos de tipo? Estoy realmente interesado en no hacer esto si es posible – Steve

0

me encontré tratando de llamar a una función miembro no const que fue heredado, pero en realidad era const debido a la API que estaba utilizando. Finalmente, establecí una solución diferente: renegociar la API para que la función que heredé esté correctamente establecida.

No siempre será posible negociar cambios en las funciones de los demás, pero hacerlo cuando sea posible parece más limpio y más agradable que la necesidad de usar const_cast y también beneficia a otros usuarios.

3

La restricción de los métodos de miembro de const viene del tiempo de compilación. Si puedes engañar al compilador, entonces sí.

class CFoo 
{ 
public: 
    CFoo() {m_Foo = this;} 
    void tee(); 

    void bar() const 
    { 
     m_Foo->m_val++; // fine 
     m_Foo->tee(); // fine 
    } 
private: 
    CFoo * m_Foo; 
    int m_Val; 

}; 

En realidad, esto anula el propósito del método constante, por lo que es mejor que no lo haga cuando el diseño de una nueva clase. No es dañino saber que hay una manera de hacerlo, especialmente se puede utilizar como solución alternativa en esta clase antigua que no estaba bien diseñada en el concepto de función de miembro de la función.

+0

¡Qué truco cobarde! ... Lo usaré :) – Olumide

Cuestiones relacionadas