ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 클래스 메서드와 데이터 멤버에 대한 포인터
    @ 16. 1 ~ 17. 1/C++ 2015. 11. 18. 19:26

    함수포인터는

    C++ 에서는

    typedef로 선언해서 해당함수의 파라미터와 리턴타입에 호환되는 함수를 이용하면되는데..

    typedef bool(*Func)(int, int); //Func 타입을 선언해서 두개의 int 파라미터와 bool타입 리턴값을 가지는 함수 포인터를 표현

    Func func1; //선언한뒤에

     

    bool test(int num1, int num2) {} //이런식의 함수가 있다면

    func1 = test; 또는 포인터이니까 func1 = &test로 하면된다.

    C++11에서는 타입 에일리어스 기능이 있어

    typedef bool(*Func)(int, int); 이걸

    이렇게 using Func = bool(*)(int, int); 이런식으로 표현이 되며

    Func func1; //똑같이 사용이 가능하다.

     

    어쨌든 지금 보려는건 이게 아니라 클래스의 멤버 변수와 메서드는 어떻게 포인터로 사용할 수 있는지..

    클래스의 멤버 또는 메서드의 주소값을 얻어 포인터 변수를 만드는 것은 C++에서는 매우 정상적인 작업이다.

    하지만 객체 인스턴스가 없다면 static멤버 static메서드만 포인터로 접근할 수 있다.

    왜냐면 기본적으로 멤버와 메서드는 개별 객체에 종속되어 존재하니까..

    이 때문에 멤버나 메서드를 포인터를 통해 접근하려면 다음과 같이 반드시 특정 객체의 맥락하에서 역참조 해야만한다.

    	

    c++ 의 문법중 대부분은 다른 oop 언의 문법과 큰 차이는 없지만, 함수 포인터는 연습이 되지 않으면 바로 써먹기 불편한점이 있다. 

    그런데 , 함수 조차 포인터로 호출 할 수 있다는것은 종전의 언어들에서 찾아 볼 수 없는 유연함을 제공 할 것으로 기대한다.


    사실 표현 방법이 조금 다를뿐 c# 의 메소드 델리게이트 , as3 의 var a = function(){...} 활용에 해당 하는것으로 파악 된다. 

    동적객체에 적용하기 위해 * 연산자를 사용하는데 어순이 조금 이색적이다.






    //

    //  main.cpp

    //  FuntionPointerStudy

    //

    //  Created by SuperSc on 2015. 1. 7..

    //  Copyright (c) 2015 SuperSc. All rights reserved.

    //


    #include <iostream>

    using namespace std;




    //정적함수

    void StaticFunction(int n)

    {

        cout << "static function int : " << n << endl;

    }




    //네임스페이스 안의 정적 함수

    namespace TestNameSpace {

        void InNameSpace(int n)

        {

            cout << "in namesapce static function : " << n << endl;

        }

    }




    // 클래스

    class TestClass

    {

        

        

    private:

        string _name;

    public:

        

        //클래스 안의 정적함수

        static void InClassStaticFuction(int n)

        {

            cout << "in class static function : " << n << endl;

        }

        

        

        TestClass(string name)

        {

            _name = name;

        }

        

        

        //클래스 함수들...

        void PrintInfo() const

        {

            cout << "in class infomation : " << _name << endl;

        }

        

        void InClass1(int n)

        {

            cout << "in class function 1 : " << n << endl;

        }

        

        void InClass2(int n)

        {

            cout << "in class function 2 : " << n << endl;

        }

        

        int Sum(int m , int n)

        {

            int _sum = m + n;

            return _sum;

        }

        

        string GetName() const

        {

            return _name;

        }

        

        

    };








    int main(int argc, const char * argv[]) {

        // insert code here...

        

        //정적함수 포인터 선언

        void (*staticFunctionPointer)(int);

        staticFunctionPointer = StaticFunction;

        staticFunctionPointer(20);

        

        

        //네임스페이스 안의 정적함수로 교체 (함수 모양이 같으면 치환이 가능하다)

        staticFunctionPointer = TestNameSpace::InNameSpace;

        staticFunctionPointer(30);

        

        

        //클래스의 정적함수로 교체

        staticFunctionPointer = TestClass::InClassStaticFuction;

        staticFunctionPointer(40);

        

        

        

        

        //

        //동적 객체 생성

        //

        TestClass * testObject1 = new TestClass("test_object_1");

        

        

        //활용 : 동적 객체의 -> 활용하여도 클래스의 정적 함수 사용가능

        staticFunctionPointer = testObject1->InClassStaticFuction;

        staticFunctionPointer(50);

        

        

        //에러 ! 동적 객체의 클래스 함수는 모양이 같더라도 정적함수 포인터로 사용 없다.

        //staticFunctionPointer = testObject1->InClass;

        

        

        //선언 : int 인수 1개를 사용하는 동적 객체용 함수 포인터 선언

        void(TestClass::*inClassFunctionPointer)(int);

        

        

        //활용 : 인수 1 함수 포인터 활용

        inClassFunctionPointer = &TestClass::InClass1;

        (testObject1->*inClassFunctionPointer)(60);

        

        

        //활용 : 역시 함수 형태가 같은 같은 동적 객체의 함수도 치환이 가능하다.

        inClassFunctionPointer = &TestClass::InClass2;

        (testObject1->*inClassFunctionPointer)(70);

        

        

        //선언 : 동적 객체의 인수를 사용하지 않는 const 함수 포인터 선언

        void(TestClass::*inClassNoArgFunction)() const;

        

        

        //활용 : 동적 객체의 인수가 없는 함수 포인터 활용

        inClassNoArgFunction = &TestClass::PrintInfo;

        (testObject1->*inClassNoArgFunction)();

        

        

        //선언 : 동적 객체의 인수가 2, 반환값이 int 함수 포인터 선언

        int(TestClass::*inClassDoubleArgFunction)(int,int);

        

        

        //활용 : 동적 객체의 인수 2, 반환값이 int 함수 포인터 활용

        inClassDoubleArgFunction = &TestClass::Sum;

        int result_int = (testObject1->*inClassDoubleArgFunction)(80,90);

        cout<< "result : " << result_int << endl;

        

        

        //선언 : 동적 객체의 반환값이 string 함수 포인터 선언

        string(TestClass::*inClassReturnStringFunction)() const;

        

        

        //활용 : 동적 객체의 반환값이 string 함수 포인터 활용

        inClassReturnStringFunction = &TestClass::GetName;

        string result_string = (testObject1->*inClassReturnStringFunction)();

        cout << "result : " << result_string << endl;

        

        

        

        delete testObject1;

        testObject1 = nullptr;

        

        

        /* 출력내용

         

         static function int : 20

         in namesapce static function : 30

         in class static function : 40

         in class static function : 50

         in class function 1 : 60

         in class function 2 : 70

         in class infomation : test_object_1

         result : 170

         result : test_object_1

         

         */

        

        

        return 0;

    }






    edit - 15.01.12

    c++ 11 부터 아래와 같이 using 을 이용해 간단히 함수 포인터를 선언 할 수 있다.

    using EventListener = void(*)(void *  , TEventArg );



    EventListener 라는 이름의 함수 포인터는 반환값이 없고 , void * 형과 TEventArg 형의 인자를 가진다.

     클래스 메서드나 데이터 멤버에 대한 포인터를 사용할 일은 많지 않지만,

    종종 일반 클래스 메서드를 포인터로서 qsort() 같은 함수에 인자로 넘기는 실수를 할 때가 있다(아래 파란색이 함수포인터니까..). 이때는 의도한 대로 동작하지 않는다..

     

    #include <stdlib.h>

     

    void qsort(void *base, size_t nel, size_t width, int (*compar)(const void *, const void *));

     

    어쨌든 non-static 맴버 / 메서드에 대해서는 객체 없이 역참조 해서는 안된다는 점은 꼭! 기억!!

Designed by Tistory.