2010-11-21 13 views
0

Ich lerne C++ und ich bin mit einem Problem fest. Ich brauche eine Möglichkeit, eine bestimmte Unterklasse innerhalb der Basisklasse zu verwenden. Macht es Sinn oder verwende ich einen falschen Ansatz? SelectBrand sollte die Unterklasse auswählen, wie kann ich das tun?Unterklasse aus Basisklasse auswählen ... möglich?

Hier unten meine vereinfachte Klassen:


----- 
class Protocol { 

public: 

    Protocol() {}; 
    ~Protocol() {}; 
    int openPort(); 
    int readPort(char *buffer); 

..... 

private: 

     Protocol (const Protocol&); 
}; 

int Protocol::openPort() {......}; 

int Protocol::readPort() {.........}; 

/***********************************************************************************/ 

class Device{ 

public: 

     Device(Protocol& port):_protocol(port){} 
     ~Device(); 
     virtual int getEvent(char *buffer) { return -1; } 
     int Device::selectBrand(); 

     .............. 

protected: 

     Protocol& _protocol; 

private: 

     int brand; 
     Device(const Device&orig); 
}; 

Device::~Device() {} 

int Device::selectBrand() { 

     ...... 

     switch (X) 

      case 1: 

        "use subclass Brand_B" 

      case 2: 

        "use subclass Brand_B" 

     ....... 

} 

/***********************************************************************************/ 

class Brand_A:public Device { 

public: 

     Brand_A(Protocol& port); 
     ~Brand_A(); 
     int getEvent(void *rawData); 

private: 

     Brand_A(const Brand_A&); 
}; 

Brand_A::Brand_A(Protocol& port):Device(port) {} 

Brand_A::~Brand_A() {} 

int Brand_A::getEvent(void *rawData) { 


      .... readPort(......); 

} 

/***********************************************************************************/ 

class Brand_B:public Device { 

public: 

     Brand_B(Protocol& port); 
     ~Brand_B(); 
     int getEvent(void *rawData); 

private: 

     Brand_B(const Brand_B&); 

}; 

Brand_B::Brand_B(Protocol& port):Device(port) {} 

Brand_B::~Brand_B() {} 

int Brand_B::getEvent(void *rawData) { 


      .... readPort(......); 

} 

/* main **********************************************************/ 

int main(int argc, char **argv) { 

     Device *mydev; 

     char *buffer; 

    .............. 

    mydev->selectBrand(); 

    .......... 

    mydev->getEvent(buffer); 

    ........... 

} 
+0

Es gibt viel zu viele '....' Abschnitte in Ihrem Beispiel. Es ist nicht klar, was 'selectBrand' tatsächlich tut: Was ist' X' und was meinst du mit "Use subclass"? – casablanca

+0

Wenn Sie mit der "Auswahl" ein Objekt verkleinern möchten, um eine Unterklasse zu "bekommen", dann ist Ihr Ansatz fehlerhaft. Ich denke, die Bereitstellung von so viel Code ist verwirrend - wie wäre es nur mit den Schlüsselklassen, Methoden und wie Sie sie verwenden möchten? – belwood

+0

'~ Device()' sollte wahrscheinlich 'virtuell' sein. – fredoverflow

Antwort

2

Dies ist keine gute Idee.

Im Allgemeinen ist die Antwort dynamic_cast, aber das spezifische Verhalten von Nachkommen einer Basisklasse aufzurufen, ist normalerweise ein schlechtes Entwurfszeichen.

Sie können versuchen, die Klassenhierarchie zu invertieren und Vorlagen zu verwenden.

0

Es sieht so aus, als würden Sie versuchen, etwas wie Polymorphie zu implementieren, wenn C++ das für Sie erledigt. Wenn Sie virtuelle Methoden in Ihrer Basisklasse definieren und diese in Ihren Unterklassen überschreiben, sollten Aufrufe dieser Methoden für einen Zeiger oder Verweis auf den Basistyp dazu führen, dass die Implementierung der Unterklasse aufgerufen wird.

Zum Beispiel:

class BaseClass 
{ 
    virtual void DoSomething() 
    { 
     printf("base"); 
    } 

}; 

class SubClass : public BaseClass 
{ 
    void DoSomething() 
    { 
     printf("sub"); 
    } 
}; 

int main() 
{ 
    BaseClass *myBase = new SubClass(); 
    myBase->DoSomething(); // should print "sub" to stdout 

    return 0; 
} 

Sie müssen wissen, welche Art abgeleitet (Art der Unterklasse), die Sie verwenden möchten, wenn Sie es schaffen, so dass die Instanz, die zusätzliche Funktionalität des abgeleiteten Typs hat. Wenn Sie dies nicht tun, erhalten Sie nur die Funktionalität der Basisklasse, und Sie können sie nur als Basisklasse behandeln (oder etwas weiter oben in der Vererbungshierarchie, wenn Ihre Basisklasse von etwas erbt).

Sie können sogar ein Mitglied verwenden, um zwischen verschiedenen Instanzen zu unterscheiden, wenn sie nichts anderes machen. Es ist schwer, anhand des Codebeispiels genau zu erkennen, was Sie tun möchten. Vielleicht würde ein konkreteres Beispiel für das, was Sie erreichen möchten, und nicht dafür, wie Sie es erreichen möchten, hilfreich sein.

+0

Mein Problem ist im Wesentlichen Ich weiß nicht, welche Unterklasse ich verwenden muss. Dies ist eine Anforderung für eine Funktion in der Basisklasse, die ich selectBrand genannt habe. Basierend auf einigen Überprüfungen verwendet der Code die Unterklasse barnd_a oder brand_b. – Luke

+0

BaseClass * myBase = neue SubClass(); wäre perfekt .... aber wenn ich mehr Subclass zur Auswahl habe? – Luke

+0

Nach dem Lesen Ihrer zweiten Post denke ich, verstehe ich das Problem ein wenig besser. Wenn Sie versuchen, verschiedene Implementierungen von Methoden zu verwenden, die in der Basisklasse deklariert sind, ohne zu wissen, welche Sie verwenden, möchten Sie wahrscheinlich das abstrakte Fabrikmuster. So etwas wie: Gerät * Gerät = Geräte :: CreateDevice(); Wobei Device eine Interface-Klasse ist, die die allgemeinen Methoden von Geräten deklariert, und die zurückgegebene Instanz ist ein bestimmtes Gerät, das von CreateDevice() bestimmt wird. – ajmccluskey

0

bitte, lassen Sie mich das Problem neu formulieren. Ich habe 1 baseClass und einige Unterklassen; Brand_A .... Brand_N

Nun, in der Hauptsache() weiß ich nicht im Voraus, welche Unterklasse ich verwenden werde; Diese Auswahl ist für eine Funktion in der Basisklasse erforderlich, die ich selectBrand genannt habe. Was ich brauche, ist ein Mechanismus, um basierend auf internen Bedingungen die richtige Unterklasse auszuwählen und zu verwenden. Ich möchte die ausgewählte Unterklasse maskieren. Wie bekomme ich das?

1

Ich dachte, ich sollte den Kommentar, den ich oben gemacht habe, konkretisieren. Zuallererst können Sie die Wikipedia-Seite für weitere Informationen über die abstract factory pattern überprüfen. Grundsätzlich können Sie auf verschiedene Implementierungen einer Schnittstelle zugreifen, wobei die verwendete Implementierung zur Laufzeit festgelegt wird. Sie wissen jedoch immer noch nicht, welche Implementierung Sie erhalten, da dies in der Factory-Methode entschieden wird, die die Implementierung der Schnittstelle zurückgibt. Daher können Sie nur die Member in der Schnittstelle und nicht eine bestimmte Implementierung verwenden. Ein Beispiel, das Ihre obigen Klassen verwendet, wäre etwa:

class Device 
{ 
    virtual int getEvent(void *rawData) = 0; 
} 

class BrandA : public Device 
{ 
    // define constructors/destructors etc. 

    int getEvent(void *rawData) 
    { 
     // BrandA's implementation for getEvent 
    } 
} 

class BrandB : public Device 
{ 
    // define constructors/destructors etc. 

    int getEvent(void *rawData) 
    { 
     // BrandB's implementation for getEvent 
    } 
} 

class DeviceFactory 
{ 
    static Device *CreateDevice(/*any parameters for determining the device?*/) 
    { 
     // You probably don't want to randomly determine which implementation you use... 
     if ((rand() % 2) == 0) 
     { 
      return new BrandA(); 
     } 
     else 
     { 
      return new BrandB(); 
     } 
    } 
} 

int main() 
{ 
    // CreateDevice will decide which type of device we use, however we can only 
    // explicitly reference the members of the base class (Device). 
    Device *myDevice = DeviceFactory::CreateDevice(); 

    myDevice->getEvent(); 

    return 0; 
} 
+0

Ja - vorausgesetzt, ich habe die Anforderungen in der Frage verstanden, ist dies definitiv der richtige Weg. Insbesondere weiß die Basisklasse nichts über die Klassen, die von ihr erben, was immer ein Zeichen dafür ist, dass alles gut läuft :-) – psmears

0

Ich habe diesen Code implementiert und getestet; es funktioniert gut. Ist es ein gutes Design oder kann es besser gemacht werden?

class BehaviorBase 
{ 
public: 
    virtual ~BehaviorBase() {} 
    virtual void DoSomethingOn(Object* obj) {} 
}; 

class Object 
{ 
public: 
    BehaviorBase* behavior; 
    void DoSomething(); 
    void ChangeBehavior(int param); 
    ~Object(); 
} 

class BehaviorA: public BehaviorBase 
{ 
    void DoSomethingOn(Object* obj) 
    { 
    printf("Behavior A\n"); 
    } 
}; 

class BehaviorB: public BehaviorBase 
{ 
    string other_data; 
    void DoSomethingOn(Object* obj) 
    { 
    printf("Behavior B\n"); 
    } 
}; 

void Object::DoSomething() 
{ 
    behavior->DoSomethingOn(this); 
} 

Object::~Object() 
{ 
    delete behavior; 
} 

void Object::ChangeBehavior(int param) 
{ 
    delete behavior; 
    switch(param) 
    { 
     case 1: behavior = new BehaviorA; break; 
     case 2: behavior = new BehaviorB; break; 
    } 
}  

int main(int argc, char **argv) { 
    int param=1; 
    Object *obj; 
    obj= new Object; 

    obj->ChangeBehavior(param); 
    obj->DoSomething();  
    delete obj; 
    return(0); 
} 
Verwandte Themen