Компиляция C ++, когда два класса ссылаются друг на друга
-
20-09-2019 - |
Вопрос
Я пытаюсь написать простую оболочку вокруг указателя соединения, которая вернет его в пул, когда оболочка будет уничтожена, но она не будет компилироваться, потому что 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);
}
Другие советы
Используйте прямое объявление:
class Connection {};
class ConnectionPool; //<<<<<<<<<<<<<<<forward declaration
class AutoConn {
//definitions
};
class ConnectionPool {
//definitions
};
реализуйте функции после точки, в которой определены классы
Правильный синтаксис для прямого объявления следующий:
class Connection; // no {}
Если вы напишете
class Connection {};
Затем вы определяете класс, и вы не можете определить класс дважды.
Кроме того, разве вы не должны быть прямолинейны, заявляя AutoConn
, не Connection
?
Прямое объявление только сообщает компилятору "такой класс существует".В вашем
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() { ... }
Возможно, вы захотите передать определение всех ConnectionPool
и AutoConn
методы, т.е.
class ConnectionPool;
class AutoConn {…};
class ConnectionPool {…};
AutoConn ConnectionPool::getConn() {
…
}
Не включайте ConnectionPool
заголовочный файл в AutoConn
.Просто используйте прямую ссылку, например class ConnectionPool;
в AutoConn
заголовочный файл.