Компиляция C ++, когда два класса ссылаются друг на друга

StackOverflow https://stackoverflow.com/questions/2447310

Вопрос

Я пытаюсь написать простую оболочку вокруг указателя соединения, которая вернет его в пул, когда оболочка будет уничтожена, но она не будет компилироваться, потому что 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 заголовочный файл.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top