bdfgdfg
[STL] 1. 함수 객체 사용해보기 본문
함수 객체
- 함수 객체는 함수처럼 호출 가능한 클래스 객체.
- 즉 함수처럼 동작하는 객체
- 함수 객체를 정의하는 방법은 '()'연사자를 오버로딩하면 된다.
함수 객체의 간단한 예시
class Functor
{
public:
void operator()(void)
{
std::cout << "함수객체 호출!" << std::endl;
}
};
int main()
{
Functor f; // 객체생성
f(); // 오버로딩된 함수 호출
return 0;
}
물론 매개변수를 넣어줄수도 있다.
class Functor
{
public:
void operator()(void)
{
std::cout << "함수객체 호출!" << std::endl;
}
void operator()(int value1,int value2)
{
std::cout << "함수객체 인자버전 호출! " << value1 << " " << value2 << std::endl;
}
};
int main()
{
Functor f;
f();
f(10, 20);
return 0;
}
이러한 함수 객체의 장점은 함수처럼 동작하는 객체이므로,
다른 멤버 변수,함수들을 가질 수 있으며 일반 함수에서는 불가능한것들이 가능해진다.
또한 속도도 일반 함수보다 함수 객체가 더 빠르다고 한다
-> 함수의 주소를 전달하여 콜백하는 경우 전달한 함수(함수 포인터)는 inline 될 수 없지만 함수 객체는 인라인 될 수 있고, 컴파일러가 쉽게 최적화가 가능하다.
장점 +, 함수 객체이기 때문에 서로 다른 객체의 내부 멤버를 직관적으로 쉽게 수정이 가능하다.
class Adder
{
public:
Adder() = default;
virtual ~Adder() = default;
public:
int operator()(int num) { return m_total += num; }
private:
int m_total = 0;
};
int main()
{
Adder add,add2;
std::cout << add(10) << std::endl;
std::cout << add2(50) << std::endl;
return 0;
}
또한 STL의 알고리즘에서 마지막 인자로 함수 포인터를 넘겨 사용자 정의에 따른 정렬등도 제공이 되는데
여기서 함수객체도 넘길 수 있다.
#include <iostream>
#include <algorithm> // for_each구문
class Functor1
{
public:
void operator()(int n) // 공백을 이용하여 원소 출력
{
std::cout << n << " ";
}
};
class Functor2
{
public:
void operator()(int n) // 각 원소를 제곱 후 공백 출력
{
std::cout << n * n << " ";
}
};
class Functor3
{
public:
void operator()(int n) // 문자열 +endl을 이용하여 원소 출력
{
std::cout << "정수 : " << n << std::endl;
}
};
int main()
{
// for_each구문은 범위내 원소들을 넘겨준 함수 포인터,함수 객체,람다등을 통해 처리한다.
int arr[5] = { 10,20,30,40,50 };
Functor1 f1;
Functor2 f2;
Functor3 f3;
std::for_each(arr, arr + 5, f1); // 객체를 넘겨준 모습. ()연산자를 오버로딩해야 가능하다!
std::cout << std::endl;
std::for_each(arr, arr + 5, f2);
std::cout << std::endl;
std::for_each(arr, arr + 5, f3);
return 0;
}
()연산자가 오버로딩된 클래스의 객체를 마지막 인자로 넘겨줄 시 알아서 ()연산자 오버로딩된 함수를 호출한다.
참고로 객체를 넘기지않고 임시 객체를 넘겨줄수도 있다.
class Functor1
{
public:
Functor1() { std::cout << "Functor1 객체 생성! \n"; }
public:
void operator()(int n) // 공백을 이용하여 원소 출력
{
std::cout << n << " ";
}
};
class Functor2
{
public:
void operator()(int n) // 각 원소를 제곱 후 공백 출력
{
std::cout << n * n << " ";
}
};
class Functor3
{
public:
void operator()(int n) // 문자열 +endl을 이용하여 원소 출력
{
std::cout << "정수 : " << n << std::endl;
}
};
int main()
{
// for_each구문은 범위내 원소들을 넘겨준 함수 포인터,함수 객체,람다등을 통해 처리한다.
int arr[5] = { 10,20,30,40,50 };
std::for_each(arr, arr + 5, Functor1()); // 임시객체를 생성해 넘겨준다.
std::cout << std::endl;
std::for_each(arr, arr + 5, Functor2());
std::cout << std::endl;
std::for_each(arr, arr + 5, Functor3());
return 0;
}
Functor1까지만 확인해보면
임시 객체 생성 후 함수가 호출이 된다.
함수 객체 구현
STL에는 유용하게 사용할 수 있는 함수 객체가 내장되어 있다.
-> 대표적인 함수객체가 바로 less와 greater
-> less는 < 연산자의 함수 객체
-> greater는 > 연산자의 함수 객체이다.
-> 또한 less와 greater는 bool형을 반환하는 조건자(predicate).
두 정수를 함수의 매개변수로 넘겨주고 '<' 연산을 수행하는 함수 객체를 본다.
class Less
{
public:
bool operator()(int a, int b)
{
return a < b;
}
};
int main()
{
Less test;
std::cout << test(10, 20) << std::endl; // test 객체를 통한 암묵적 함수 호출
std::cout << test(20, 10) << std::endl;
std::cout << Less()(50, 10) << std::endl; // 임시 객체를 통한 암묵적 함수 호출.
std::cout << Less()(10, 50) << std::endl;
std::cout << test.operator()(20,30) << std::endl; // test 객체를 통한 명시적 호출
std::cout << Less().operator()(30, 20) << std::endl; // 임시 객체를 통한 명시적 호출
return 0;
}
이렇게 '()'연산자가 오버로딩된 함수를 호출하는 방법도 여러가지가 존재한다.
단 그게 의미하는바가 무엇인지는 알고있어야한다.
STL의 less 함수 객체를 이용해보자.
std::less의 멤버를 확인해보면 실제 '()'연산자가 오버로딩된것을 알 수 있다.
int main()
{
std::less<int> l;
std::cout << l.operator()(50, 40) << std::endl;
std::cout << l(20, 30) << std::endl;
std::cout << std::less<int>()(60, 70) << std::endl;
return 0;
}
less나 greater와 같은 함수객체를 이용하여, STL의 sort(정렬)나 priority_queue등 정렬을 어떻게할지(오름차순,내림차순)
최대힙인지 최소힙인지를 위의 함수 객체를 건내주면 간편하게 사용할 수 있다.
int main()
{
int arr[10] = { 5,3,10,20,1,60,100,40,30,67 };
sort(arr, arr + 10, std::less<int>()); // 오름차순
for (int i = 0; i < 10; ++i)
std::cout << arr[i] << " ";
return 0;
}
prioirty_queue도 마찬가지
int main()
{
std::priority_queue<int, std::vector<int>, std::greater<int>> pq;
for (int i = 0; i < 10; ++i)
pq.push(i + 1);
for (int i = 0; i < 10; ++i)
{
std::cout << pq.top() << std::endl;
pq.pop();
}
return 0;
}
최소힙인 모습.
greater는 정반대 내림차순,최대힙.
'게임프로그래밍 > STL' 카테고리의 다른 글
[C++ STL] std::queue (컨테이너 어댑터) (0) | 2022.01.29 |
---|---|
[C++ STL] std::stack (컨테이너 어댑터) (0) | 2022.01.29 |
[C++ STL] std::deque (시퀀스 컨테이너) (0) | 2022.01.28 |
[C++ STL] std::list (시퀀스 컨테이너) (0) | 2022.01.28 |
[C++ STL] std::vector (시퀀스 컨테이너) (0) | 2022.01.27 |