Один метод для выполнения того же самого с разными переменными

#c #templates

#c #шаблоны

Вопрос:

у меня есть что-то вроде этого

 class Foo {
    Bar a, b, c;

    void doStuffWithA();
    void doStuffWithB();
    void doStuffWithC();
}
  

вместо написания реализации для каждого из методов я хочу что-то вроде шаблона. Как это сделать?

Приветствую, Дирк

Редактировать:

Мне явно нужно знать, с какой переменной я что-то делаю (рекурсия):

 class Foo {
    Bar a, b, c;
    Foo* parent;

    static void doRecursiveStuffWithA(Foo *_node) {
        if(_node->parent==NULL) {

            return;
        } else {
            doRecursiveStuffWithA(_node->parent)
        }

    }
    static void doRecursiveStuffWithB(Foo *_node) {
        if(_node->parent==NULL) {
            return;
        } else {
            doRecursiveStuffWithB(_node->parent)
        }

    }
    static void doRecursiveStuffWithC(Foo *_node) {
        if(_node->parent==NULL) {
            return;
        } else {
            doRecursiveStuffWithC(_node->parent)
        }

    }

}
  

Правка2:

Возможно, это лучше объясняет, в чем заключается моя проблема:

 class Foo {
public:
    int a, b, c;

}

class Bar {
public:
    void doStuffWithAOfFoo(Foo *_foo);
    void doStuffWithBOfFoo(Foo *_foo);
    void doStuffWithCOfFoo(Foo *_foo);

}
  

Я просто хочу, чтобы мой код был простым и не приходилось трижды реализовывать doStuffWithX…

Комментарии:

1. Что вы имеете в виду под «чем-то вроде шаблона»? Почему этого void doStuff(Bar x) недостаточно?

2. Потому что я хочу проделать то же самое с a, b и c. На самом деле, doStuffWithX — это рекурсивная функция в моем примере…

3. Каким образом функция с Bar параметром не решает эту проблему?

4. Одна вещь: if(parent==NULL) не будет работать в статической функции, если Foo* parent она также не является статической.

5. посмотрите правку, возможно, это я, и я просто заблокирован…

Ответ №1:

Я думаю, вам нужны параметры…

 class Foo {
    Bar a, b, c;

    void doStuffWithBar(Bar x);
}
  

Шаблоны предназначены для работы с различными типами данных, а аргументы функции предназначены для работы с различными переменными.

Комментарии:

1. Это возможно x , это должна быть либо ссылка, либо указатель некоторого типа.

Ответ №2:

У @Andrew White самый простой ответ. Если вам нужна функция, которая может делать то же самое, но с множеством разных значений, она должна принимать аргумент.

Бывают случаи, когда мы законно хотят разные методы, которые выглядят почти идентично, как getFirstName() , setFirstName() , getLastName() , setLastName() . Там, используя аргументы, предпочел бы поражение цели.

Архитектура там идеально продумана (и действительно широко принята); единственная проблема — это утомительность ввода всего этого. Если вы просто хотите избежать дополнительного ввода текста, рассмотрите возможность использования интегрированной среды разработки, которая предлагает «шаблоны кода». И Eclipse, и Visual Studio (среди многих других, конечно) позволят вам выбрать переменную и нажать кнопку, чтобы сгенерировать средство получения и установки для этой переменной. Весь код без каких-либо проблем.

Ответ №3:

Вы можете использовать ссылку:

 class Foo {
    Bar a, b, c;

    void doStuffWithBar(Baramp; what)
    {
        print(what);
        bool flag = check(what);
        if (!flag)
            doStuffWithBar(what);
    }
}
  

Вы можете использовать указатель на элемент:

 class Foo {
    Bar a, b, c;
    typedef Bar (Foo::*PointerToBar);

    void doStuffWithBar(PointerToBar selector)
    {
        print(this->*selector);
        bool flag = check(this->*selector);
        if (!flag)
            doStuffWithBar(selector);
    }
}
  

Последнее решение более гибкое: вы можете выбрать другой объект и / или другой элемент, с помощью которого продолжить рекурсию (указатели на элементы неясны и используются редко; не используйте их, если вам не нужна такая гибкость):

 class Foo {
    Bar a, b, c;
    Foo* next;
    typedef Bar (Foo::*PointerToBar);

    void doStuffWithBar(PointerToBar selector)
    {
        print(this->*selector);
        if (next)
            next->doStuffWithBar(selector);
    }
}
  

Ответ №4:

Запах кода — проблема с дизайном? Из-за повторения здесь кажется, что Bar нужен новый метод:

 void Bar::doStuff(Foo amp;foo);
  

Затем вам нужно выяснить, что такое public , private и const .

Редактировать: Ваша правка немного меняет ситуацию. Теперь я действительно чувствую, что есть способы улучшить ваш дизайн, например, контейнер STL и алгоритмы.

Ответ №5:

Чтобы немного расширить информацию о решениях Эндрю, вы также можете искать:

 void doStuffWithBar(Bar x, Bar y, Bar z);
  

Если у вас действительно есть BarX x, BarY y и BarZ z, то вы, вероятно, захотите перегрузить свою функцию-член в своем классе

 class Foo {
BarX x;
BarY y;
BarZ z;

void doStuffWithBar(BarX x);
void doStuffWithBar(BarY y);
void doStuffWithBar(BarZ z);
};
  

Вы также можете искать что-то вроде (это самое уродливое решение, и я бы его не рекомендовал):

 void doStuffWithBar(int n)
{
    if(n==0)
          doSomethingWithX();
    else if(n==1)
          doSomethingWithY();
    else if(n==2)
          doSomethingWithZ();
}
  

Редактировать:

 ReturnType Bar::doStuffWithBar(ParamA a, ParamB b);
  

Комментарии:

1. последний был на самом деле тем, о чем я думал в первую очередь, но, как и вы, я думаю, что это очень некрасиво…

2. Значит, все три элемента являются объектом одного типа (Bar)?

3. Вы хотите, чтобы рекурсивная функция выполняла точно такое же действие, только с другим объектом?

4. то же самое с разными переменными разных объектов.

5. Тогда, я думаю, вам следует добавить метод doStuffWithBar() в класс Bar. Если вам нужны параметры из Foo, передайте их в качестве параметров при вызове метода. Я отредактировал выше.