5

I am trying to write a simple wrapper around a connection pointer that will return it to the pool when the wrapper is destroyed, but it wont compile because the ConnectionPool and AutoConn need each other to be declared.

I tried to use forward deceleration but it didn't work. How do I solve this? (using 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);
    }
};
Peter Alexander
  • 53,344
  • 14
  • 119
  • 168
Omry Yadan
  • 31,280
  • 18
  • 64
  • 87
  • 2
    design wise this is a BAD idea, you should try to remove the circular dependancy! – NomeN Mar 15 '10 at 13:29
  • well, it's a localized issue and the benefit of not having to worry about releasing the connection (in face of possible exceptions) far outweigh the "badness" of this design problem. – Omry Yadan Mar 15 '10 at 13:32
  • possible duplicate of http://stackoverflow.com/questions/2233149/two-classes-and-inline-functions –  Mar 31 '10 at 15:15

7 Answers7

6

A combination of forward declaration and separation of declaration from definition of members with circular dependencies works. For example:

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);
}
Clifford
  • 88,407
  • 13
  • 85
  • 165
4

Use forward declaration:

class Connection {};

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

class AutoConn {
//definitions
};

class ConnectionPool {
//definitions
};
sharptooth
  • 167,383
  • 100
  • 513
  • 979
3

implement the functions after the point where the classes are defined

stefaanv
  • 14,072
  • 2
  • 31
  • 53
3

The correct syntax for a forward declaration is:

class Connection; // no {}

If you write

class Connection {};

Then you are defining the class, and you can't define a class twice.

Also, shouldn't you be forward declaring AutoConn, not Connection?

Peter Alexander
  • 53,344
  • 14
  • 119
  • 168
1

Forward declaration only tells the compiler "such a class exists". In your

AutoConn getConn()

since AutoConn is a value type, the whole structure of AutoConn must be known, so forward declaration of the class won't work. So you must put the actual declaration of AutoConn before ConnectionPool.

In your AutoConn, the type ConnectionPool is only referred by pointers. In this case the whole structure of ConnectionPool is not required, so forward declaration of ConnectionPool is enough.

Therefore you need to rearrangement the classes into this:

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

But notice that

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

these methods require the compiler to know the members of ConnectionPool, so a complete structure is needed. To solve this problem the definition must be placed after ConnectionPool. Thus only the constructors and destructors should remain.

class AutoConn {
  ...
  AutoConn(ConnectionPool* pool, Connection *c);
  ~AutoConn();
}
class ConnectionPool { ... };
AutoConn::AutoConn(ConnectionPool* pool, Connection *c) : ... { ... }
AutoConn::~AutoConn() { ... }
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
0

You might want to outsource the definition of all ConnectionPool and AutoConn methods, i.e.

class ConnectionPool;
class AutoConn {…};

class ConnectionPool {…};

AutoConn ConnectionPool::getConn() {
   …
}
Alexander Gessler
  • 45,603
  • 7
  • 82
  • 122
0

Don't include ConnectionPool header file in AutoConn. Just use a forward reference like class ConnectionPool; in the AutoConn header file.

Naveen
  • 74,600
  • 47
  • 176
  • 233