Как избежать дублирования кода в общих классах - PullRequest
2 голосов
/ 13 марта 2012

У меня есть функция обратного вызова, называемая

MyCallBack(int type)

, и у меня есть 3 класса B, C и D, производных от A, имеющих общее имя метода. В настоящее время мой код похож на

MyCallBack(int type){
if(type == 1 ){
B b;
b.perform();
}else if(type==2) {
C c;
c.perform();
}else if(type ==3){
D d; 
d.perform();
}
* 1006.* Есть ли способ, которым я могу уменьшить этот код что-то вроде
MyCallBack(int type){
Common object(type);
object.perform();
}

Ответы [ 4 ]

3 голосов
/ 13 марта 2012

По сути, вам нужен полиморфизм.

Все ваши классы B, C, D должны быть производными от абстрактного класса, скажем SuperBase, с чисто виртуальным методом perform().
Ваш код должен использовать только указатель на SuperBase, который содержит адрес фактического конкретного объекта класса.
Как только вы это сделаете, в зависимости от фактического типа объекта будет вызван метод из соответствующего класса.

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

2 голосов
/ 13 марта 2012
Идея

@ Алса об использовании полиморфизма хороша (IMO), но она действительно работает только после , которую вы преобразовали из входного целого числа в фактический тип. Один из способов сделать это состоит в том, чтобы проиндексировать массив указателей на объекты:

MyCallback(int type) { 
    static A *ptrs[] = { new B, new C, new D};

    ptrs[type-1]->perform();
}

Редактировать: на тот случай, если вы не знали, чтобы это работало правильно, perform должна быть виртуальной функцией, объявленной (возможно, как чистая) виртуальной в A и определенной в каждом из B, C и D. Необходимо убедиться, что вся подпись функции, а не только имя, одинакова между классами.

1 голос
/ 13 марта 2012

Как насчет интерфейса ?

class A
{
    public:

        virtual void perform() = 0;
};

class B : public A
{
    public:

        void perform() { ... }
};

// Same for C, and D

, поэтому ваш обратный вызов будет выглядеть следующим образом:

MyCallBack(A& performer)
{
    performer.perform();
}

Если вы не можете изменить подписьобратный вызов, как насчет абстрактного шаблона фабрики :

function A* AFactory(int type)
{
    switch(type)
    {
        case 1: return new B();    // Assuming B, C, D all derive from A
        case 2: return new C();
        case 3: return new D();
        default: return nullptr;  // nullptr is a c++11 thing.  Use NULL, if you're still on C++03
    }
}

и затем обратного вызова ...

MyCallBack(int type)
{
    std::unique_ptr<A> obj(AFactory(type));  // this will automatically release the memory once it falls out of scope
    obj->perform();
}
0 голосов
/ 13 марта 2012

Вы должны создать Object Factory или просто статический (глобальный) метод, возвращающий указатель (или ссылку, может быть) на базовый тип, но состоящий из объекта производного типа.

CBase* CreateObjectBasedOnType(int type)
{
    // check for type and return appriopriate derived object
}

MyCallBack(int type)
{
    CreateObjectBasedOnType(type)->perform();
}

Обратите внимание, что методы, которые вы хотите вызвать, должны быть виртуальными.

Еще лучше можно использовать шаблоны

template<typename T>
MyCallBack()
{
    T Obj;
    Obj.perform();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...