Я пытаюсь записать простую обертку вокруг указателя соединения, который возвратит ее пулу, когда обертка будет уничтожена, но это компиляция привычки, потому что ConnectionPool и AutoConn нужен друг друг, чтобы быть объявленными.
Я пытался использовать вперед замедление, но оно не работало. Как я решаю это? (использующий 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);
}
};
Комбинация прямого объявления и отделения объявления от определения членов с круговыми зависимостями работает. Например:
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);
}
Вы можете передать определение всех ConnectionPool
и AutoConn
методы, то есть
class ConnectionPool;
class AutoConn {…};
class ConnectionPool {…};
AutoConn ConnectionPool::getConn() {
…
}
Прямое объявление только сообщает компилятору, что «такой класс существует».В вашем
AutoConn getConn()
, поскольку AutoConn
является типом значения, вся структура AutoConn
должна быть известна, поэтому предварительное объявление класса не будет работать. Таким образом, вы должны поместить фактическое объявление AutoConn
перед ConnectionPool
.
В вашем AutoConn
тип ConnectionPool
упоминается только указателями. В этом случае вся структура ConnectionPool
не требуется, поэтому достаточно прямого объявления ConnectionPool
.
Следовательно, вам необходимо переупорядочить классы так:
class Connection;
class ConnectionPool;
class AutoConn { ... };
class ConnectionPool { ... };
Но обратите внимание, что
AutoConn(ConnectionPool* pool, Connection *c) : m_pool(pool), m_connection(c) {}
~AutoConn()
{
m_pool->releaseConnection(m_connection);
}
эти методы требуют, чтобы компилятор знал члены ConnectionPool
, поэтому необходима полная структура. Чтобы решить эту проблему, определение необходимо поместить после ConnectionPool
. Таким образом, должны остаться только конструкторы и деструкторы.
class AutoConn {
...
AutoConn(ConnectionPool* pool, Connection *c);
~AutoConn();
}
class ConnectionPool { ... };
AutoConn::AutoConn(ConnectionPool* pool, Connection *c) : ... { ... }
AutoConn::~AutoConn() { ... }
Используйте прямое объявление:
class Connection {};
class ConnectionPool; //<<<<<<<<<<<<<<<forward declaration
class AutoConn {
//definitions
};
class ConnectionPool {
//definitions
};
Не включайте файл заголовка ConnectionPool
в AutoConn
. Просто используйте прямую ссылку, например class ConnectionPool;
в заголовочном файле AutoConn
.
Правильный синтаксис для прямого объявления таков:
class Connection; // no {}
Если вы пишете
class Connection {};
Тогда вы определяете класс, а вы не можете определить класс дважды.
Также, разве вы не должны объявлять вперед AutoConn
, а не Connection
?