Вот как вы можете это сделать, используя циклы.
public static int[][] makeCopy(int[][] array){
b=new int[array.length][];
for(int row=0; row<array.length; ++row){
b[row]=new int[array[row].length];
for(int col=0; col<b[row].length; ++col){
b[row][col]=array[row][col];
}
}
return b;
}
Функтор является в значительной степени просто классом, который определяет оператор (). Это позволяет Вам создать объекты, которые похожи" на функцию:
// this is a functor
struct add_x {
add_x(int x) : x(x) {}
int operator()(int y) const { return x + y; }
private:
int x;
};
// Now you can use it like this:
add_x add42(42); // create an instance of the functor class
int i = add42(8); // and "call" it
assert(i == 50); // and it added 42 to its argument
std::vector<int> in; // assume this contains a bunch of values)
std::vector<int> out(in.size());
// Pass a functor to std::transform, which calls the functor on every element
// in the input sequence, and stores the result to the output sequence
std::transform(in.begin(), in.end(), out.begin(), add_x(1));
assert(out[i] == in[i] + 1); // for all i
существует несколько хороших вещей о функторах. Каждый - это в отличие от регулярных функций, они могут содержать состояние. Вышеупомянутый пример создает функцию, которая добавляет 42 к тому, что Вы даете ему. Но то значение 42 не является hardcoded, оно было определено как аргумент конструктора, когда мы создали наш экземпляр функтора. Я мог создать другой сумматор, который добавил 27, только путем вызова конструктора с различным значением. Это делает их приятно настраиваемыми.
, Поскольку последние строки показывают, Вы часто передаете функторы как аргументы другим функциям, таким как станд.:: преобразуйте или другие стандартные алгоритмы библиотеки. Вы могли сделать то же с указателем регулярной функции кроме, как я сказал выше, функторы могут быть "настроены", потому что они содержат состояние, делая их более гибкими (Если бы я хотел использовать указатель функции, я должен был бы записать функцию, которая добавила точно 1 к ее аргументу. Функтор является общим, и добавляет, что Вы инициализировали его с), и они также потенциально более эффективны. В вышеупомянутом примере компилятор знает точно, какая функция std::transform
должна вызвать. Это должно звонить add_x::operator()
. Это означает, что может встроить тот вызов функции. И это делает его столь же эффективным, как будто я вручную вызвал функцию на каждом значении вектора.
, Если я передал указатель функции вместо этого, компилятор не мог бы сразу видеть, на какую функцию он указывает на, поэтому если он не выполняет некоторую довольно сложную глобальную оптимизацию, он должен был бы разыменовать указатель во времени выполнения, и затем выполнить вызов.
Как другие упомянули, функтор является объектом, который действует как функция, т.е. он перегружает оператор вызова функции.
Функторы являются наиболее часто используемыми в алгоритмах STL. Они полезны, потому что они могут содержать состояние прежде и между вызовами функции, как закрытие на функциональных языках. Например, Вы могли определить MultiplyBy
функтор, который умножает его аргумент на указанную сумму:
class MultiplyBy {
private:
int factor;
public:
MultiplyBy(int x) : factor(x) {
}
int operator () (int other) const {
return factor * other;
}
};
Тогда Вы могли передать MultiplyBy
объект к алгоритму как станд.:: преобразуйте:
int array[5] = {1, 2, 3, 4, 5};
std::transform(array, array + 5, array, MultiplyBy(3));
// Now, array is {3, 6, 9, 12, 15}
Другое преимущество функтора по указателю на функцию состоит в том, что вызов может быть встроен в большем количестве случаев. При передаче указателя функции transform
если , что вызов был встроен и компилятор не знает, что Вы всегда передаете ту же функцию ему, это не может встроить вызов через указатель.
Функтор является объектом, который действует как функция. В основном, класс, который определяет operator()
.
class MyFunctor
{
public:
int operator()(int x) { return x * 2;}
}
MyFunctor doubler;
int x = doubler(5);
реальное преимущество состоит в том, что функтор может содержать состояние.
class Matcher
{
int target;
public:
Matcher(int m) : target(m) {}
bool operator()(int x) { return x == target;}
}
Matcher Is5(5);
if (Is5(n)) // same as if (n == 5)
{ ....}
Мало дополнения. Можно использовать boost::function
, для создания функторов из функций и методов, как это:
class Foo
{
public:
void operator () (int i) { printf("Foo %d", i); }
};
void Bar(int i) { printf("Bar %d", i); }
Foo foo;
boost::function<void (int)> f(foo);//wrap functor
f(1);//prints "Foo 1"
boost::function<void (int)> b(&Bar);//wrap normal function
b(1);//prints "Bar 1"
и можно использовать повышение:: свяжите для добавления состояния к этому функтору
boost::function<void ()> f1 = boost::bind(foo, 2);
f1();//no more argument, function argument stored in f1
//and this print "Foo 2" (:
//and normal function
boost::function<void ()> b1 = boost::bind(&Bar, 2);
b1();// print "Bar 2"
и самый полезный с повышением:: свяжите и повысьте:: функция можно создать функтор из метода класса, на самом деле это - делегат:
class SomeClass
{
std::string state_;
public:
SomeClass(const char* s) : state_(s) {}
void method( std::string param )
{
std::cout << state_ << param << std::endl;
}
};
SomeClass *inst = new SomeClass("Hi, i am ");
boost::function< void (std::string) > callback;
callback = boost::bind(&SomeClass::method, inst, _1);//create delegate
//_1 is a placeholder it holds plase for parameter
callback("useless");//prints "Hi, i am useless"
можно создать список или вектор функторов
std::list< boost::function<void (EventArg e)> > events;
//add some events
....
//call them
std::for_each(
events.begin(), events.end(),
boost::bind( boost::apply<void>(), _1, e));
существует одна проблема со всем этим материалом, ошибка компилятора обменивается сообщениями, не человекочитаемо:)
Имя «функтор» традиционно использовалось в теории категорий задолго до того, как на сцене появился C ++. Это не имеет ничего общего с концепцией функтора в C ++. Это' Лучше использовать имя объект функции вместо того, что мы называем «функтором» в C ++. Так другие языки программирования вызывают аналогичные конструкции.
Используется вместо простой функции:
Особенности:
Минусы:
Используется вместо указателя функции:
Особенности:
Минусы:
Используется вместо виртуальной функции:
Характеристики:
Минусы: