Pregunta

Existe de todos modos una especie de virtual estática miembro en C++?

Por ejemplo:

class BaseClass {
    public:
        BaseClass(const string& name) : _name(name) {}
        string GetName() const { return _name; }
        virtual void UseClass() = 0;
    private:
        const string _name;
};


class DerivedClass : public BaseClass {
    public:
        DerivedClass() : BaseClass("DerivedClass") {}
        virtual void UseClass() { /* do something */ }
};

Sé que este ejemplo es trivial, pero si tengo un vector de datos complejos que va a ser siempre el mismo para todos los de la clase derivada, pero que se necesita para acceder desde la base de los métodos de la clase?

class BaseClass {
    public:
        BaseClass() {}
        virtual string GetName() const = 0;
        virtual void UseClass() = 0;
};


class DerivedClass : public BaseClass {
    public:
        DerivedClass() {}
        virtual string GetName() const { return _name; }
        virtual void UseClass() { /* do something */ }
    private:
        static const string _name;
};

string DerivedClass::_name = "DerivedClass";

Esta solución no satify mí porque necesito reimplementar el miembro _name y su descriptor de acceso GetName() en cada clase.En mi caso tengo varios miembros que sigue _name comportamiento y décimas de clases derivadas.

Alguna idea?

¿Fue útil?

Solución

Aquí hay una solución:

struct BaseData
{
  const string my_word;
  const int my_number;
};

class Base
{
public:
    Base(const BaseData* apBaseData)
    {
        mpBaseData = apBaseData;
    }
    const string getMyWord()
    {
        return mpBaseData->my_word;
    }
    int getMyNumber()
    {
        return mpBaseData->my_number;
    }
private:
    const BaseData* mpBaseData;
};

class Derived : public Base
{
public:
    Derived() : Base(&sBaseData)
    {
    }
private:
    static BaseData sBaseData;
}

BaseData Derived::BaseData = { "Foo", 42 };

Otros consejos

Parece que la respuesta está en la pregunta, el método sugerido que parece ser la dirección correcta para ir, excepto que si usted tiene un gran número de los miembros compartidos que usted podría desear para reunir en una estructura o clase y de ese pasado como argumento al constructor de la clase base.

Si usted insiste en tener el "compartir" los miembros implementado como miembros estáticos de la clase derivada, usted podría ser capaz de generar de forma automática el código de las clases derivadas.XSLT es una gran herramienta para la auto-generación de clases sencillas.

En general, el ejemplo no muestra una necesidad de "virtual estática" de los miembros, debido a que para fines como estos en realidad no necesita de la herencia - en lugar usted debe utilizar la clase base y tienen que aceptar los valores apropiados en el constructor - tal vez la creación de una única instancia de los argumentos para cada "sub-tipo" y pasando un puntero a la misma para evitar la duplicación de los datos compartidos.Otro enfoque similar es el uso de plantillas y pase como argumento de plantilla de una clase que proporciona todos los valores relevantes (esto se conoce comúnmente como la "Política" patrón).

Para concluir - con el propósito de que el ejemplo original, no hay necesidad de tales virtual "estática" de los miembros.Si usted todavía piensa que son necesarios para que el código está escrito, por favor, trate de elaborar y añadir más contexto.

Ejemplo de lo que he descrito anteriormente:

class BaseClass {
    public:
        BaseClass(const Descriptor& desc) : _desc(desc) {}
        string GetName() const { return _desc.name; }
        int GetId() const { return _desc.Id; }
        X GetX() connst { return _desc.X; }
        virtual void UseClass() = 0;
    private:
        const Descriptor _desc;
};


class DerivedClass : public BaseClass {
    public:
        DerivedClass() : BaseClass(Descriptor("abc", 1,...)) {}
        virtual void UseClass() { /* do something */ }
};

class DerDerClass : public BaseClass {
    public:
        DerivedClass() : BaseClass("Wowzer", 843,...) {}
        virtual void UseClass() { /* do something */ }
};

Me gustaría profundizar en esta solución, y tal vez dar una solución a el problema de inicialización:

Con un pequeño cambio, puede implementar el diseño descrito anteriormente, sin la necesidad de crear una nueva instancia de la "descriptor" para cada instancia de una clase derivada.

Usted puede crear un objeto singleton, DescriptorMap, que contendrá la instancia única de cada descriptor, y utilizarlo en la construcción de la deriva objetos como:

enum InstanceType {
    Yellow,
    Big,
    BananaHammoc
}

class DescriptorsMap{
    public:
        static Descriptor* GetDescriptor(InstanceType type) {
            if ( _instance.Get() == null) {
                _instance.reset(new DescriptorsMap());
            }
            return _instance.Get()-> _descriptors[type];
        }
    private:
        DescriptorsMap() {
            descriptors[Yellow] = new Descriptor("Yellow", 42, ...);
            descriptors[Big] = new Descriptor("InJapan", 17, ...)
            ...
        }

        ~DescriptorsMap() {
            /*Delete all the descriptors from the map*/
        }

        static autoptr<DescriptorsMap> _instance;
        map<InstanceType, Descriptor*> _descriptors;
}

Ahora podemos hacer esto:

class DerivedClass : public BaseClass {
    public:
        DerivedClass() : BaseClass(DescriptorsMap.GetDescriptor(InstanceType.BananaHammoc)) {}
        virtual void UseClass() { /* do something */ }
};

class DerDerClass : public BaseClass {
    public:
        DerivedClass() : BaseClass(DescriptorsMap.GetDescriptor(InstanceType.Yellow)) {}
        virtual void UseClass() { /* do something */ }
};

Al final de la ejecución, cuando el tiempo de ejecución de C realiza uninitializations, también se llama al destructor de objetos estáticos, incluyendo nuestro autoptr, que elimina en nuestro ejemplo de la DescriptorsMap.

Así que ahora tenemos una sola instancia de cada descriptor que también se eliminan al final de la ejecución.

Tenga en cuenta que si el único propósito de la clase derivada es la oferta de la "descriptor" de datos (es decir,como oposición a la implementación de las funciones virtuales), entonces usted debe hacer ver con la elaboración de la base de la clase no abstracta, y la creación de una instancia con el correspondiente descriptor de cada momento.

Estoy de acuerdo con Hershi la sugerencia de utilizar una plantilla como la "clase base".De lo que usted está describiendo, suena más como un uso de plantillas en lugar de crear subclases.

Se podría crear una plantilla como la siguiente ( no he probado a compilar este ):


template <typename T>
class Object
{
public:

  Object( const T& newObject ) : yourObject(newObject) {} ;
  T GetObject() const { return yourObject } ;
  void SetObject( const T& newObject ) { yourObject = newObject } ;

protected:

  const T yourObject ;
} ;

class SomeClassOne
{
public:

  SomeClassOne( const std::vector& someData )
  {
    yourData.SetObject( someData ) ;
  }

private:

  Object<std::vector<int>> yourData ;
} ;

Esto permitirá utilizar la plantilla de la clase de métodos para modificar los datos según sea necesario desde dentro de las clases personalizadas que utilizan los datos y compartir los diversos aspectos de la clase de plantilla.

Si estás decidido sobre el uso de la herencia, entonces usted podría tener que recurrir a las "alegrías" de usar un puntero void* en su clase base y el trato con la fundición, etc.

Sin embargo, basado en su explicación, me parece que la necesidad de plantillas y no por herencia.

@Hershi:el problema con este enfoque es que cada instancia de cada clase derivada tiene una copia de los datos, que puede ser costoso en alguna manera.

Tal vez usted podría intentar algo como esto (estoy escupir bolas sin una compilación de ejemplo, pero la idea debe ser clara).


#include <iostream>
#include <string>
using namespace std;

struct DerivedData
{
  DerivedData(const string & word, const int number) :
    my_word(word), my_number(number) {}
  const string my_word;
  const int my_number;
};

class Base {
public:
  Base() : m_data(0) {}
  string getWord() const { return m_data->my_word; }
  int getNumber() const { return m_data->my_number; }
protected:
  DerivedData * m_data;
};


class Derived : public Base {
public:
  Derived() : Base() {
    if(Derived::s_data == 0) {
      Derived::s_data = new DerivedData("abc", 1);
    }
    m_data = s_data;
  }
private:
  static DerivedData * s_data;
};


DerivedData * Derived::s_data = 0; 

int main()
{
  Base * p_b = new Derived();
  cout getWord() << endl;
}

Respecto a la pregunta de seguimiento sobre la eliminación del objeto estático:la única solución que viene a la mente es el uso de un puntero inteligente, algo así como el Impulso compartido puntero.

Suena como si usted está tratando de evitar tener que duplicar el código en la hoja de clases, así que ¿por qué no sólo se derivan de un intermedio de la clase base de la clase base.esta clase intermedia puede contener los datos estáticos, y tiene todas sus hojas las clases derivan de el intermedio de la clase base.Esto presupone que uno estático pieza de datos sobre todas las clases derivadas se desea, lo que parece así que a partir de su ejemplo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top