2010-03-15 12 views
5

Estoy tratando de escribir un envoltorio simple alrededor de un puntero de conexión que lo devolverá al grupo cuando se destruya el envoltorio, pero no se compilará porque ConnectionPool y AutoConn se necesitan mutuamente para ser declarado.Compilación de C++ cuando dos clases se refieren entre sí

Intenté usar la deceleración hacia adelante pero no funcionó. ¿Cómo puedo solucionar esto? (Con g ++)

class Connection {}; 

class ConnectionPool 
{ 
    Connection *m_c; 
public: 
    AutoConn getConn() 
    { 
     return AutoConn(this, m_c); // by value 
    } 

    void releaseConnection(Connection *c) 
    { 
    } 
}; 

class AutoConn 
{ 
    ConnectionPool* m_pool; 
    Connection *m_connection; 
public: 
    AutoConn(ConnectionPool* pool, Connection *c) : m_pool(pool), m_connection(c) {} 
    ~AutoConn() 
    { 
     m_pool->releaseConnection(m_connection); 
    } 
}; 
+2

diseño esta es una MALA idea, ¡debería intentar eliminar la dependencia circular! – NomeN

+0

bueno, es un problema localizado y el beneficio de no tener que preocuparse por la liberación de la conexión (frente a posibles excepciones) supera con creces la "maldad" de este problema de diseño. –

+0

posible duplicado de http://stackoverflow.com/questions/2233149/two-classes-and-inline-functions –

Respuesta

6

Combinación de declaración directa y separación de declaración de la definición de miembros con trabajos de dependencias circulares. Por ejemplo:

class Connection {}; 
class ConnectionPool ; 

class AutoConn 
{ 

    ConnectionPool* m_pool; 
    Connection *m_connection; 
public: 
    AutoConn(ConnectionPool* pool, Connection *c) : m_pool(pool), m_connection(c) {} 
    ~AutoConn() ; // Not defined here because it accesses unknown members of class Connection 
} ; 

class ConnectionPool 
{ 
    Connection *m_c; 
public: 
    AutoConn getConn() 
    { 
     return AutoConn(this, m_c); // by value 
    } 

    void releaseConnection(Connection *c) 
    { 
    } 
}; 

// Definition of destructor with class Connection member dependencies. 
AutoConn::~AutoConn() 
{ 
    m_pool->releaseConnection(m_connection); 
} 
+0

genial, finalmente una respuesta real :). ¡Gracias! –

4

Uso declaración adelantada:

class Connection {}; 

class ConnectionPool; //<<<<<<<<<<<<<<<forward declaration 

class AutoConn { 
//definitions 
}; 

class ConnectionPool { 
//definitions 
}; 
+0

Le sugiero que intente compilarlo. no compila –

3

implementar las funciones después del punto en el que las clases se definen

0

Es posible que desee externalizar la definición de todos los ConnectionPool y AutoConn métodos , es decir,

class ConnectionPool; 
class AutoConn {…}; 

class ConnectionPool {…}; 

AutoConn ConnectionPool::getConn() { 
    … 
} 
3

The co rrecta sintaxis de declaración a seguir es:

class Connection; // no {} 

Si se escribe

class Connection {}; 

estamos definiendo la clase, y no se puede definir una clase dos veces.

Además, ¿no deberías estar adelante declarando AutoConn, no Connection?

+0

esto no es desaceleración directa, solo es una desaceleración por lo que la muestra compilada. –

+0

No lo definió dos veces; esa es la * única * definición de Conexión. Supongo que es solo un titular de lugar para reducir la cantidad de código publicado. – Clifford

+0

Oh, pensé que era su intento de la declaración directa, mis disculpas. –

0

No incluye el archivo de encabezado ConnectionPool en AutoConn. Solo use una referencia directa como class ConnectionPool; en el archivo de encabezado AutoConn.

1

La declaración directa solo le dice al compilador que "tal clase existe". En su

AutoConn getConn() 

desde AutoConn es un tipo de valor, toda la estructura de AutoConn debe ser conocido, por lo que la declaración de avance de la clase no va a funcionar. Por lo tanto, debe colocar la declaración real de AutoConn antes de ConnectionPool.

En su AutoConn, el tipo ConnectionPool solo se menciona mediante punteros. En este caso, no se requiere la estructura completa de ConnectionPool, por lo que la declaración directa de ConnectionPool es suficiente.

lo tanto es necesario reordenamiento, las clases en esto:

class Connection; 
class ConnectionPool; 
class AutoConn { ... }; 
class ConnectionPool { ... }; 

notar que

AutoConn(ConnectionPool* pool, Connection *c) : m_pool(pool), m_connection(c) {} 
~AutoConn() 
{ 
    m_pool->releaseConnection(m_connection); 
} 

estos métodos requieren el compilador para conocer a los miembros de ConnectionPool, por lo que es necesaria una estructura completa. Para resolver este problema, la definición debe colocarse después de ConnectionPool. Por lo tanto, solo los constructores y destructores deberían permanecer.

class AutoConn { 
    ... 
    AutoConn(ConnectionPool* pool, Connection *c); 
    ~AutoConn(); 
} 
class ConnectionPool { ... }; 
AutoConn::AutoConn(ConnectionPool* pool, Connection *c) : ... { ... } 
AutoConn::~AutoConn() { ... } 
+0

esta es también una respuesta correcta. +1 por la buena respuesta. –

Cuestiones relacionadas