2010-03-15 7 views
5

Tôi đang cố gắng viết một trình bao bọc đơn giản xung quanh một con trỏ kết nối sẽ trả về hồ bơi khi trình bao bọc bị hủy, nhưng nó sẽ không biên dịch vì ConnectionPool và AutoConn cần nhau được khai báo.Soạn thảo C++ khi hai lớp tham chiếu đến nhau

Tôi đã cố gắng sử dụng giảm tốc chuyển tiếp nhưng không hoạt động. Tôi giải quyết điều này như thế nào? (Sử dụng 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); 
    } 
}; 
+2

thiết kế khôn ngoan đây là ý tưởng BAD, bạn nên cố gắng loại bỏ phụ thuộc vòng tròn! – NomeN

+0

tốt, đó là một vấn đề địa phương hóa và lợi ích của việc không phải lo lắng về việc phát hành kết nối (đối mặt với trường hợp ngoại lệ có thể) vượt xa "xấu" của vấn đề thiết kế này. –

+0

có thể trùng lặp của http://stackoverflow.com/questions/2233149/two-classes-and-inline-functions –

Trả lời

6

Kết hợp khai báo và tách khai báo từ định nghĩa thành viên với công việc phụ thuộc vòng. Ví dụ:

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); 
} 
+0

tuyệt vời, cuối cùng là một câu trả lời thực sự :). cảm ơn! –

4

Sử dụng phía trước tuyên bố:

class Connection {}; 

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

class AutoConn { 
//definitions 
}; 

class ConnectionPool { 
//definitions 
}; 
+0

Tôi đề nghị bạn cố gắng biên dịch nó. nó không biên dịch. –

3

thực hiện các chức năng sau khi điểm mà các lớp được định nghĩa

0

Bạn có thể muốn thuê ngoài định nghĩa của tất cả ConnectionPoolAutoConn phương pháp , tức là

class ConnectionPool; 
class AutoConn {…}; 

class ConnectionPool {…}; 

AutoConn ConnectionPool::getConn() { 
    … 
} 
3

Đồng cú pháp rrect cho một tờ khai chuyển tiếp là:

class Connection; // no {} 

Nếu bạn viết

class Connection {}; 

Sau đó, bạn được xác định lớp, và bạn không thể định nghĩa một lớp hai lần.

Ngoài ra, bạn không nên chuyển tiếp tuyên bố AutoConn, không phải Connection?

+0

đây không phải là giảm tốc, nó chỉ là một sự giảm tốc để mẫu được biên dịch. –

+0

Ông không định nghĩa nó hai lần; đó là định nghĩa * duy nhất của kết nối. Tôi giả sử nó chỉ là một người giữ chỗ để giảm số lượng mã được đăng. – Clifford

+0

Ồ, tôi nghĩ đó là nỗ lực của bạn trong tuyên bố về phía trước - lời xin lỗi của tôi. –

0

Không bao gồm ConnectionPool tệp tiêu đề trong AutoConn. Chỉ cần sử dụng tham chiếu chuyển tiếp như class ConnectionPool; trong tệp tiêu đề AutoConn.

1

Tuyên bố chuyển tiếp chỉ cho trình biên dịch biết "một lớp tồn tại". Trong bạn

AutoConn getConn() 

từ AutoConn là một loại giá trị, toàn bộ cấu trúc của AutoConn phải được biết, vì vậy khai phía trước của lớp sẽ không hoạt động. Vì vậy, bạn phải đặt tờ khai thực tế của AutoConn trước ConnectionPool.

Trong số AutoConn, loại ConnectionPool chỉ được giới thiệu bởi con trỏ. Trong trường hợp này, toàn bộ cấu trúc của ConnectionPool là không bắt buộc, vì vậy việc khai báo trước là ConnectionPool là đủ.

Vì vậy, bạn cần phải sắp xếp các lớp học vào này:

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

Nhưng chú ý rằng

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

những phương pháp này đòi hỏi trình biên dịch biết các thành viên của ConnectionPool, do đó, một cấu trúc hoàn chỉnh là cần thiết. Để giải quyết vấn đề này, định nghĩa phải được đặt sau ConnectionPool. Vì vậy, chỉ có các nhà xây dựng và destructors nên vẫn còn.

class AutoConn { 
    ... 
    AutoConn(ConnectionPool* pool, Connection *c); 
    ~AutoConn(); 
} 
class ConnectionPool { ... }; 
AutoConn::AutoConn(ConnectionPool* pool, Connection *c) : ... { ... } 
AutoConn::~AutoConn() { ... } 
+0

đây cũng là câu trả lời đúng. 1 cho câu trả lời tốt. –