Compilazione C ++ quando due classi si riferiscono l'uno all'altro
-
20-09-2019 - |
Domanda
Sto cercando di scrivere un semplice wrapper per un puntatore di connessione che restituirà alla piscina quando l'involucro è distrutto, ma non lo compilo perché il ConnectionPool e AutoConn bisogno l'uno dell'altro per essere dichiarato.
Ho provato ad usare la decelerazione in avanti, ma non ha funzionato. Come lo risolvo? (Usando 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);
}
};
Soluzione
Una combinazione di dichiarazione anticipata e la separazione di dichiarazione definizione dei membri con dipendenze circolari opere. Ad esempio:
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);
}
Altri suggerimenti
Usa dichiarazione anticipata:
class Connection {};
class ConnectionPool; //<<<<<<<<<<<<<<<forward declaration
class AutoConn {
//definitions
};
class ConnectionPool {
//definitions
};
implementare le funzioni dopo il punto in cui sono definite le classi
La sintassi corretta per una dichiarazione anticipata è:
class Connection; // no {}
Se si scrive
class Connection {};
Poi si sta definendo la classe, e non si può definire una classe due volte.
Inoltre, non si dovrebbe essere in avanti dichiarando AutoConn
, non Connection
?
dichiarazione anticipata dice solo al compilatore "quali esiste una classe". Nel vostro
AutoConn getConn()
poiché AutoConn
è un tipo di valore, l'intera struttura della AutoConn
deve essere nota, dichiarazione così avanti della classe non funzionerà. Quindi è necessario mettere la dichiarazione effettiva di AutoConn
prima ConnectionPool
.
Nel vostro AutoConn
, il tipo ConnectionPool
viene indicato solo da puntatori. In questo caso non è richiesto l'intera struttura di ConnectionPool
, dichiarazione così in avanti del ConnectionPool
è sufficiente.
Pertanto è necessario riarrangiamento le classi in questo modo:
class Connection;
class ConnectionPool;
class AutoConn { ... };
class ConnectionPool { ... };
Ma notare che
AutoConn(ConnectionPool* pool, Connection *c) : m_pool(pool), m_connection(c) {}
~AutoConn()
{
m_pool->releaseConnection(m_connection);
}
questi metodi richiedono al compilatore di conoscere i membri della ConnectionPool
, quindi è necessario una struttura completa. Per risolvere questo problema la definizione deve essere posizionato dopo ConnectionPool
. Così solo i costruttori e distruttori dovrebbero rimanere.
class AutoConn {
...
AutoConn(ConnectionPool* pool, Connection *c);
~AutoConn();
}
class ConnectionPool { ... };
AutoConn::AutoConn(ConnectionPool* pool, Connection *c) : ... { ... }
AutoConn::~AutoConn() { ... }
Si potrebbe voler esternalizzare la definizione di tutti i metodi e ConnectionPool
AutoConn
, cioè.
class ConnectionPool;
class AutoConn {…};
class ConnectionPool {…};
AutoConn ConnectionPool::getConn() {
…
}
Non includere ConnectionPool
file di intestazione in AutoConn
. Basta usare un riferimento in avanti come class ConnectionPool;
nel file di intestazione AutoConn
.