2012-08-25 19 views
6

Por ejemplo, proponer map<int,void*>hold donde void* siempre almacena punteros desde classA ¿es seguro volver a lanzarlo más tarde mediante static_cast?¿Está bien para static_cast un puntero void *

classA* ptr = static_cast<classA*>(holditerator->second); 

la razón void* se utiliza es porque hold es miembro de una clase definida en un encabezado utilizado por algunos archivos cpp que no saben lo que es classA. Tendría que incluir el encabezado de las definiciones classA en estos archivos cpp, lo que no se puede hacer por muchos motivos.

+1

¿Por qué harías esto? Proporcione más contexto, ya que es probable que haya una solución más adecuada. – Johnsyweb

+0

¿Por qué no usa un mapa en primer lugar? – BatchyX

+0

@BatchyX Supongo que 'hold' no solo contiene classA *? –

Respuesta

13

Sí, static_cast está bien en ese caso y es lo correcto para usar.

Tengo que preguntar por qué no almacena punteros classA* en primer lugar. Si quiere poner punteros de clase derivados en él, entonces cuidado con, necesita subir/subir (implícita o explícitamente) los punteros de clase derivados a classA*antes de ponerlos en el mapa.

Pero incluso si coloca también punteros de clase derivados en el mapa, un puntero de clase base sería suficiente porque un puntero de clase derivado es implícitamente convertible en un puntero de clase base.

El motivo void * se utiliza porque hold es miembro de una clase define en un encabezado utilizado por algunos archivos cpp que no saben qué clase es.

Esa puede ser una razón válida para evitar violaciones de capas.

Tendría que incluir el encabezado de las definiciones de clase A en estos archivos cpp que no se puede hacer por muchos motivos.

Probablemente no sea necesario en su caso. Una declaración anticipada es suficiente. Si el encabezado sabe qué se pone en el mapa, pero solo quiere evitar la inclusión de encabezados adicionales, este es el camino a seguir.

+0

He editado la pregunta –

2

Escribir void * en la cabecera sólo porque los usuarios del mapa no deben saber sobre el tipo real es no una buena idea, ya que se pierde la seguridad de tipos en todas partes de su código, incluso en lugares que sabemos acerca claseA .

Considere

  1. derivar claseA de una clase que cada parte de su código puede conocer,
  2. envolver el mapa en un objeto que proporciona una interfaz con aquellas partes del código que tienen que hacer frente a el mapa, pero no con claseA,
  3. declarar, pero no la definición de clase ClassA en el archivo de cabecera (puede ser peligroso si los objetos son destruidos en algún lugar en el que se declara claseA, pero no definidos),
  4. el uso de plantillas,
  5. implementando la clase que contiene el mapa como una subclase derivada, de modo que el campo del mapa se puede poner en la subclase derivada.

Punto 5: Ilustración (= patrón de plantilla)

En lugar de

class Containing { 
    private: 
     map<int,void*> myMap; 
    public: 
     void somePublicFunction() { // ...implementation } 
}; 

que escribir

// Containing.h 
class Containing { 
    protected: 
     virtual void doSomething() = 0; 
    public: 
     static Containing* Create(); 
     void somePublicFunction() { doSomething(); } 
     virtual ~Containing() { } 
}; 

// Containing.cc 
#include ContainingImplementation.h 
Containing* Containing::Create() { return new ContainingImplementation; } 

// ContainingImplementation.h/cc 
class ContainingImplementation : public Containing { 
    protected: 
     virtual void doSomething() { // ... } 
    private: 
     map<int,ClassA*> myMap; 
    public: 
     virtual ~ContainingImplementation() { } 
}; 
6

Como se explicó Johannes, el static_cast está bien. Otra técnica para evitar las dependencias a ClassA en los archivos cpp es usar el pimpl idiom.

// in header file 
class classB { 
public: 
    classB(); 
    ~classB(); 
private: 
    class impl; 
    unique_ptr<impl> pimpl; 
}; 



// in implementation file 
#include "classA.hpp" 

class classB::impl 
{ 
    std::map<int, classA> hold; // hidden in implementation file 
}; 

classB::classB() : pimpl{ new impl{ /*...*/ } } { } 
classB::~classB() { } 
+1

excelente idea :) –

Cuestiones relacionadas