Выбрать подкласс из базового класса ... возможно? - PullRequest
0 голосов
/ 22 ноября 2010

Я изучаю C ++ и застрял с проблемой. Мне нужен способ использовать определенный подкласс в базовом классе. Имеет ли это смысл или я использую неправильный подход? SelectBrand должен выбрать подкласс, как я могу это сделать?

Здесь под моими упрощенными классами:


-----
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);

    ...........

}

Ответы [ 5 ]

2 голосов
/ 22 ноября 2010

Это не очень хорошая идея.

Обычно ответом является dynamic_cast, но вызов определенного поведения потомков из базового класса обычно является плохим признаком разработки.

Вы можете попробоватьинвертирование иерархии классов и использование шаблонов.

1 голос
/ 23 ноября 2010

Я подумал, что должен конкретизировать комментарий, который я сделал выше. Прежде всего, вы можете посетить страницу Википедии для получения дополнительной информации о абстрактном шаблоне фабрики . По сути, он позволяет получить доступ к различным реализациям интерфейса, причем используемая реализация определяется во время выполнения. Тем не менее, вы все еще не знаете, какую реализацию вы получите, как это решено в фабричном методе, который возвращает реализацию интерфейса. В результате вы можете использовать только элементы интерфейса, а не конкретную реализацию. Пример, который использует ваши классы выше, будет выглядеть примерно так:

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 голосов
/ 23 ноября 2010

Я реализовал и протестировал этот код;это работает отлично.Это хороший дизайн или лучше?

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);
}
0 голосов
/ 22 ноября 2010

пожалуйста, позвольте мне переформулировать проблему. У меня есть 1 базовый класс и несколько подклассов; Brand_A .... Brand_N

Теперь в main () я заранее не знаю, какой подкласс я буду использовать; этот выбор требуется для функции в базовом классе, который я назвал selectBrand. Что мне нужно, так это механизм выбора и использования правильного подкласса на основе внутренних условий. Я хочу маскировать на основной () выбранный подкласс. Как это получить?

0 голосов
/ 22 ноября 2010

Похоже, вы пытаетесь реализовать что-то вроде полиморфизма, когда C ++ сделает это за вас.Если вы определяете виртуальные методы в базовом классе и переопределяете их в своих подклассах, вызовы этих методов по указателю или ссылка на базовый тип должны привести к вызову реализации подкласса.

Например:

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;
}

Вы должны знать, какой производный тип (тип подкласса) вы хотите использовать при его создании, чтобы экземпляр имел дополнительные функциональные возможности производного типа.Если вы этого не сделаете, все, что вы получите, - это функциональность базового класса, и вы не можете рассматривать его как что-либо, кроме базового класса (или чего-либо еще выше иерархии наследования, если ваш базовый класс наследует от чего-то).* Возможно, вы даже захотите использовать элемент для различения разных экземпляров, если они на самом деле не делают ничего другого.Из примера кода сложно сказать, что именно вы хотите сделать.Может быть, поможет более конкретный пример того, чего вы пытаетесь достичь, а не того, как вы пытаетесь достичь этого.

...