#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, передайте их в качестве параметров при вызове метода. Я отредактировал выше.