es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

C++ Cómo anular un campo de clase con un tipo diferente (sin plantilla)?

Entonces estoy tratando de escribir un intérprete simple en c++, pero me encontré con algunos problemas. Tengo una clase “Token” que contiene un enum “TokenType” y un objeto “TokenValue”. La clase “TokenValue” es la clase base de varias otras clases (“TV_String”, “TV_Int” y “TV_Float”).

Aquí está el código para “TokenValue” y sus clases hijas:
“`c++
// TokenValue.h

class TokenValue
{
public:
void* value = NULL;

<pre><code>virtual bool operator ==(const TokenValue& tv) const
{
return typeid(this) == typeid(tv) && value == tv.value;
}
</code></pre>

};

class TV_Empty : public TokenValue {};

class TV_String : public TokenValue
{
public:
std::string value;

<pre><code>TV_String(std::string value); // Los constructores simplemente asignan el argumento de valor al campo de valor
</code></pre>

};

class TV_Int : public TokenValue
{
public:
int value;

<pre><code>TV_Int(int value);
</code></pre>

};

class TV_Float : public TokenValue
{
public:
float value;

<pre><code>TV_Float(float value);
</code></pre>

};

<pre><code><br />Aquí está el código para "Token":
“`c++
// Token.h

class Token
{
public:
enum class TokenType
{
// todos los diferentes tipos
}

TokenType type;
TokenValue value;

Token(TokenType type, TokenValue value); // solo inicializa el tipo y el valor, nada más
};

El problema que tengo es que el campo “value” no se está cambiando cuando utilizo alguna de las clases hijas (siempre muestra 00000000 cuando lo imprimo, supongo que es el valor de “void* value = NULL”, pero no estoy seguro). Según mi investigación, creo que podría resolverse utilizando plantillas, pero en mi caso no puedo usar plantillas porque el “Token” nunca conoce el tipo de su correspondiente “TokenValue”.

Entonces, ¿cómo puedo anular el tipo y el valor del campo “value” y acceder al valor correcto en las clases hijas y en el operador ==?

(Gracias a Jarod42 me di cuenta de que no “sobrescribe” el campo, sino que crea un nuevo campo con un tipo diferente y el mismo nombre.)

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Una solución al problema sería usar funciones virtuales en la clase TokenValue para acceder y modificar el campo de valor. Esto permitiría que cada clase hija tenga su propia implementación para acceder y modificar su respectivo campo de valor.

    Por ejemplo, la clase TokenValue podría tener las siguientes funciones virtuales:

    “`c++
    class TokenValue
    {
    public:
    virtual void* getValue() const = 0;
    virtual void setValue(void* newValue) = 0;

    virtual bool operator ==(const TokenValue& tv) const
    {
        return typeid(*this) == typeid(tv) && getValue() == tv.getValue();
    }
    

    };


    Y cada clase hija debería implementar estas funciones: ```c++ class TV_Int : public TokenValue { public: int value; TV_Int(int value) : value(value) {} void* getValue() const override { return reinterpret_cast<void*>(&value); } void setValue(void* newValue) override { value = *reinterpret_cast<int*>(newValue); } }; class TV_Float : public TokenValue { public: float value; TV_Float(float value) : value(value) {} void* getValue() const override { return reinterpret_cast<void*>(&value); } void setValue(void* newValue) override { value = *reinterpret_cast<float*>(newValue); } };

    Luego, en la clase Token, puedes usar un puntero a TokenValue en lugar de un objeto TokenValue. Esto te permite almacenar cualquier clase hija de TokenValue en el campo value:

    “`c++
    class Token
    {
    public:
    enum class TokenType
    {
    // todos los diferentes tipos
    };

    TokenType type;
    TokenValue* value;
    
    Token(TokenType type, TokenValue* value)
        : type(type), value(value) {}
    
    ~Token()
    {
        delete value;
    }
    

    };


    Ahora, para acceder y modificar el campo de valor, utilizarías las funciones virtuales de `TokenValue`: ```c++ TokenValue* tokenValue = new TV_Int(42); Token* token = new Token(TokenType::INT, tokenValue); int intValue = *reinterpret_cast<int*>(token->value->getValue()); // acceder al valor *reinterpret_cast<int*>(token->value->getValue()) = 43; // modificar el valor

    Y la función operator== también funcionará correctamente y comparará los valores reales:

    c++
    bool equal = *tokenValue == *otherTokenValue; // comparación usando operator==

    Ten en cuenta que también necesitas agregar un destructor virtual a TokenValue para asegurarte de que se llame al destructor correcto al eliminar una clase hija a través de un puntero a la clase base.</int></int></float></void></int></void>

Comments are closed.