Jag vet inte hur du löste problemet, men när två klasser behöver direkt prata med varandra är man oftast ute på hal is. Ett vanligt sätt, design pattern, för att komma undan detta är att införa ytterligare en klass emellan de två klasserna som sköter kommunikationen åt ena hållet.
Ta exemplet att man vill göra en ftp-klient och lägger själva protokoll-hanteringen i en klass CFtpClient och användargränssnittet i en klass CApplicationWindow.
CApplicationWindow äger typiskt en CFtpClient, och kan anropa dess metoder (som exempelvis Connect, GetFile och PutFile).
Samtidigt kanske man i användargränssnittet vill visa en procent-stapel på hur mycket som hämtats av en fil, eller status under en Connect. Den första tanken är att CFtpClient ska anropa tillbaka till CApplicationWindow (med metoder som exempelvis SetStatus eller GotDisconnected).
Problemet blir då ett obehagligt cirkulärberoende. Istället inför man en klass "CStatusReceiver", som är abstrakt - en så kallad "protokollklass". Dess enda uppgift är att tala om på vilket sätt CFtpClient ska meddela CApplicationWindow vad som händer. CApplicationWindow ärver, eller "implementerar" protokollklassen CStatusReceiver.
Ungefär såhär skulle det kunna se ut:
// Abstrakt klass, används enkom för att skicka data
// mellan användar-gränssnittet och ftp-hanteraren.
// Den här skulle typiskt ha fler metoder, typ
// OnConnected(), OnTransferCompleted, OnConnectionLost etc.
class CStatusReceiver
{
public:
virtual void OnStatus(const char* statusText) = 0;
};
// Själva protokoll-hanteringen. Den här skulle typiskt ha fler
// metoder, typ Connect(), GetFile(), PutFile().
class CFtpClient
{
public:
CStatusReceiver* m_pStatusReceiver;
CFtpClient(CStatusReceiver* pStatusReceiver) : m_pStatusReceiver(pStatusReceiver)
{
}
// Anropas för att koppla upp mot en server. Skickar
// statusmedddelanden till CStatusReceiver för att
// indikera vad som händer.
void Connect(const char* ipAddress, unsigned port)
{
//
m_pStatusReceiver->OnStatus("Connecting to...");
}
};
class CApplicationWindow : public CStatusReceiver
{
CFtpClient* m_pFtp;
public:
CApplicationWindow() : m_pFtp(NULL)
{
m_pFtp = new CFtpClient(this);
}
virtual ~CApplicationWindow()
{
delete m_pFtp;
}
// CStatusReceivers metod som anropas av CFtpClient-medlemmen då den vill meddela ny status
void OnStatus(const char* statusText)
{
// Uppdatera statustext, exempelvis m_LogWindow->AddText(statusText);
}
};
Med denna lösning vet både CFtpClient och CApplicationWindow om CStatusReceiver.
CApplicationWindow känner dessutom till CFtpClient.
Inga cirkulära beroenden finns.