C ++: перебор объектов для вызова одного и того же метода - PullRequest
2 голосов
/ 01 апреля 2012

В C ++, скажем, у вас есть целая куча объектов, которые вы хотите вызвать одним и тем же методом.

Alice->callSameMethod();
Bob->callSameMethod();
...
Yoyo->callSameMethod();

Но сложно набрать одну и ту же строку от Алисы до Йойо.Есть ли способ сделать что-то вроде:

For (each x in {Alice,Bob, ..., Yoyo}) x->callSameMethod;

Я видел for_each здесь: http://www.cplusplus.com/reference/algorithm/for_each/, но не понял этого.

Ответы [ 4 ]

5 голосов
/ 01 апреля 2012

Пример:

class Base{public: virtual int callSameMethod() = 0;};
           //pure virtual, can make it a default implementation
class Alice: public Base {public: int callSameMethod();...}; // own implementation
class Bob: public Base {public: int callSameMethod();...}; // own implementation
class YoYo: public Base{public: int callSameMethod();...}; // own implementation

Где-то в вашем коде:

Base* p1 = new Alice();
Base* p2 = new Bob();

std::vector<Base*> v;
std::vector<Base*>::iterator it;
v.push_back(p1);
v.push_back(p2);
for (it = v.begin(); it != v.end(); it++) (*it)->callSameMethod();

Это называется «полиморфизмом», и ваш базовый класс определяет общий интерфейс, с помощью которого вы можете вызывать любые производные, не зная, какого именно типа они есть. Вы можете использовать std::for_each вместо простого цикла или использовать vector с индексированным доступом вместо итераторов, как вам будет угодно.

1 голос
/ 23 марта 2015

Все объекты должны иметь общий базовый тип или быть одного типа.

class Base { public: virtual void callSameMethod() = 0; }; // abstract base
class Derived1 : public Base { public: virtual void callSameMethod() {:::}; };
class Derived2 : public Base { public: virtual void callSameMethod() {:::}; };

// instances
Base* Alice = new Derived1;
Base* Bob   = new Derived2;
Base* YoYo  = new Derived1;

Если у вас есть это, наиболее элегантное решение зависит от вашей версии C ++.

In C ++ 03 Вы можете создать контейнер, который включает указатели на все элементы

Base* const list[] = {Alice, Bob, YoYo};

и выполнять итерацию по нему, используя обычный цикл for

int length = (sizeof(list) / sizeof(Base*));
for(int i = 0; i < length; ++i) list[i]->callSameMethod();

или std:: for_each

#include <algorithm>
#include <functional>

std::for_each(list, list + length, std::mem_fun(&Base::callSameMethod));

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

Если у вас есть компилятор, который поддерживает C ++ 11 , однако существует гораздо более простое решение:

#include <initializer_list>

for (auto i : {Alice, Bob, YoYo}) i->callSameMethod();

Обратите внимание, что все элементы в списке инициализатора должны бытьс указателем того же типа, Base*.Если это не так, тип списка инициализатора должен быть явно указан:

// alternative declarations with different pointer types
Derived1* Alice = new Derived1;
Derived2* Bob   = new Derived2;
Derived1* YoYo  = new Derived1;

auto objects = std::initializer_list<Base*>{Alice, Bob, YoYo};
for (auto i : objects) i->callSameMethod();
0 голосов
/ 01 апреля 2012

Такого рода вещи можно сделать, если они полиморфны.Если все они наследуются от одного и того же класса (что, вероятно, должно быть, если у них всех есть общие методы), вы можете хранить их все в std::vector указателей типа базового класса.Тогда это просто вопрос цикла по вектору и вызова этого метода.

т.е.

for ( std::vector<BaseClass*>::iterator it = objectsVec.begin(); 
                                        it != objectsVec.end();
                                        ++it )
{
    (*it)->callSameMethod();
}
0 голосов
/ 01 апреля 2012

Вам нужно, чтобы все объекты, содержащие callSameMethod (), наследовали один и тот же интерфейс, где callSameMethod () - это виртуальная функция. Таким образом, вы можете использовать «for_each», чтобы делать то, что вы хотите. Кстати, вам нужен и функтор.

...