반응형
728x90
반응형

std::function이 필요한 이유부터 설명하겠다.

위는 함수 포인터로 객체의 멤버함수를 가리킬려고 온갖 발악을 하지만.. 되지 않는 광경을 보고 있다. 35번 줄은 말도 안되기 때문에 에러부터 난다.

왜 에러가 날까?

1. = 연산자를 기준으로 타입이 맞지 않다.

2. C++에서는 객체의 멤버 함수의 이름은 해당 함수의 주소 값으로 변환되지 않는다. 즉, 객체 멤버 함수의 이름으로는 함수의 주소 값을 알 수 없다는 것이다.

3. 설령, 주소를 어떻게 넣는다고 하더라도, 해당 주소의 함수가 어떤 객체의 것인지 알 수가 없다.

뭐 아무튼 그래서 36번 라인과 40번 라인처럼 기이한 방법으로 사용한다... 나의 의도가 아니다 ㅋㅋㅋㅋㅋ

이런 설정인데, 예로 보겠다.

예 중 하나인데, 번호 순서대로 읽으면 되며, 배열 형태로도 가능하며, 단일 형태로도 할당이 가능하다.

위의 예를 호출하는 문장이다.

아래와 같이 객체를 () 연산자 오버로딩한 객체, functor 또한 std::function으로 담아낼 수 있다.

 

그리고 또한 멤버 함수 또한 받을 수 있는데 이 또한 예제로 보겠다.

 

아래에 전체 코드와 실행 결과를 확인해보겠다. 먼저, 함수 포인터를 이용한 예제이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
 
using namespace std;
 
class A
{
        private:
                int n;
        public:
                A(int a):n(a)
                {
                }
                void memberFunc(void)
                {
                        cout<<"n:"<<this->n<<endl;
                        return;
                }
};
 
void normalFunc(void)
{
        cout<<"call()!!"<<endl;
        return;
}
 
int main(void)
{
        A a(100);
 
        void (*nfunc)(void);
        void (*mfunc)(void);
        void (A::*mmfunc)(void);
 
        nfunc = normalFunc;
        // mfunc = a.memberFunc;
        mmfunc = &A::memberFunc;
 
        nfunc();
        // mfunc();
        (a.*mmfunc)();
 
        return 0;
}
cs

다음은 std::function에 대한 전체 예제이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <functional>
#include <string>
#include <iostream>
 
class A
{
        private:
                std::string name;
        public:
                A(const char * _name)
                {
                        this->name = _name;
                }
                void AFunc()
                {
                        std::cout<<"AFunc() Call! name : "<<this->name<<std::endl;
                        return;
                }
};
 
struct S
{
        void operator()(const std::string& str)
        {
                std::cout<<"S::operator() Call! : "<<str<<std::endl;
                return;
        }
};
 
int main(void)
{
        A a("Kim");
        A b("Yoo");
 
        int m = 100;
 
        std::function<int(intint)> operators[] =
        {
                [](int n1, int n2) -> int { return n1 + n2; },
                [](int n1, int n2) -> int { return n1 - n2; },
                [](int n1, int n2) -> int { return n1 * n2; },
                [](int n1, int n2) -> int { return n1 / n2; },
                [](int n1, int n2) -> int { return n1 % n2; },
                [m](int num1, int num2) -> int { return m*num1 + m*num2; },
        };
 
        std::function<void(const std::string& str)> f1 = S();
 
        std::function<void(A&)> FirstNameFunc = &A::AFunc;
 
        std::cout<<"operators[0] : "<<operators[0](55)<<std::endl;
        std::cout<<"operators[1] : "<<operators[1](55)<<std::endl;
        std::cout<<"operators[2] : "<<operators[2](55)<<std::endl;
        std::cout<<"operators[3] : "<<operators[3](55)<<std::endl;
        std::cout<<"operators[4] : "<<operators[4](55)<<std::endl;
        std::cout<<"operators[5] : "<<operators[5](55)<<std::endl;
 
        std::string str = "Hi Hello~";
        f1(str);
        FirstNameFunc(a);
        FirstNameFunc(b);
 
        return 0;
}
cs

728x90
반응형
728x90
반응형

함수 포인터와 void 포인터

  • 함수 포인터

함수 또한 메모리 상에 바이너리 형태로 올라가 호출 시 실행이 되는데, 메모리 상에 저장된 함수의 주소 값을 저장하는 포인터 변수가 함수 포인터 변수이다.

배열의 이름이 배열의 시작 주소 값을 의미하듯이 함수의 이름 또한 함수가 저장된 메모리 공간의 시작 주소 값을 의미한다.

함수 이름의 포인터 형은 반환 타입과 매개변수의 선언을 통해 결정 짓도록 약속. , 반환 타입과 매개변수의 선언이 일치하는 모든 함수들의 포인터 형은 모두 같다.

9번 라인과 10번 라인에서 볼 수 있듯이

반환 타입 (*포인터변수이름) (매개 변수) = 함수 이름

다음과 같은 형태로 함수 포인터 변수를 선언하고 함수의 주소를 받아서 12, 13번 라인처럼 함수 포인터 변수를 통한 함수 호출이 가능하다.

  • Void 형 포인터 ( 자료 형이 없는 포인터 )

다음과 같이 선언되는 포인터를 void 형 포인터 변수라고 한다.

Void 형 포인터는 어떤 변수의 주소 값이든 함수의 주소 값이든 상관 없이 주소값의 경우는 무엇이든 전부 담을 수 있다. 다음 예는 void * 변수에 다양한 주소 값을 저장하는 예를 나타낸 것이다.

, void 형 포인터 p를 이용하여 참조를 하는 순간(=포인터 연산을 하는 순간) 컴파일 에러가 발생한다. 왜냐하면 void * 포인터는 포인터 연산 시 증감의 크기에 대한 정보가 단 한 부분도 없다. , 해당 주소로부터 어느 범위까지 연산을 하여 참조를 해야하는지에 대한 정보가 없기 때문에 참조(포인터 연산)가 불가능하다.

void형 포인터는 주소 값을 저장하는 것에만 의미를 두고 포인터 형은 나중에 결정한 참조하는 경우에 유용하게 사용된다 -> 동적 메모리 할당

  • Main 함수를 통한 인자 전달

위의 예제에서 argc는 파일 이름을 포함한 전달 되어온 인자의 수를 나타내고, argv는 더블 포인터 형태로 싱글 포인터 혹은 싱글 포인터 배열의 각 요소를 가리킨다. , argv는 두 번째 결과에서 “./t”, “yoo”, “seung”, “ho”의 주소 값인 char * 타입을 가리키기 때문에 더블 포인터 형태이다.

728x90
반응형

'컴퓨터 언어 정리 > C 언어' 카테고리의 다른 글

16 구조체  (0) 2020.10.12
15 문자와 문자열  (0) 2020.09.29
13 다차원배열 및 포인터의 관계  (0) 2020.09.21
12 포인터의 포인터  (0) 2020.09.15
11 다차원 배열  (0) 2020.09.14

+ Recent posts