본문 바로가기
코스웨어/15년 스마트컨트롤러

20150612 (바뀐 번호)31번 - 홍준모 - c# : 델리게이트의 기본 개념, windowform 활용 c++ :

by 알 수 없는 사용자 2015. 6. 12.
728x90
반응형

c#


델리게이트(Delegate) 란, 해석하면 '대리인 이라는 뜻의 Method를 참조하는 변수 이다.

굳이 비교하자면 c++의 함수 포인터와 비슷하다 라는 글을 담고 있는 사이트가 있었는데 정확히 어떻게 구동되는 지는 좀더 활용해봐야 알 듯 하다.


대리라는 말은 보통 내가 해야할 일을 다른 누군가에 위임하는 것을 뜻한다.

나를 대리할 사람이 있다면, 그로써 우리는 많은 수고를 덜을 수 있다는 점에서 나온 것이 델리게이트 인 것이다.

ex > 부모님의 심부름을 동생에서 시킴, 배가 고플 때 동생에게 라면을 끓이게 함


이런 대리인의 역활을 해주는 변수가 바로 델리게이트(Delegate) 이다.

다시 정확히 정리하자면, 델리게이트는 메소드를 대신해서 호출하는 역활을 한다.(메소드의 대리인 -> 즉 위임자.<위임하는 입장 : 메소드, 위임받는 입장 : 델리게이트>)

지금까지는 특정 메소드를 처리할 때 그 메소드를 직접 호출하여 실행시켜야 했지만, 델리게이트를 활용하면 그 메소드를 대신해서 호출할 수 있다.



델리게이트로 특정 메소드를 대신 호출하기 위해서는

1. 우선 그 메소드와 동일한 타입의 델리게이트 타입을 선언해야 한다.


delegate void typeA(void);    //void funcA(void)

delegate void typeB(void);    //void funcB(int)

delegate float typeC(void);    //float funcC(float)

delegate string typeD(void);    //string funcD(int)


메소드 타입은 매개변수와 반환타입에 의해 결정, 즉, 델리게이트 타입도 그 메소드와 동일한 매개변수, 반환타입으로 선언해주면 되는 것이다.


2. 그리고 선언한 델리게이트 타입으로 델리게이트 변수를 생성하고, 생성한 델리게이트 변수에 해당 메소드를 참조시킨다.

//delegate 변수 생성


typeA delegate0;


typeB delegate1;


typeC delegate2;


typeD delegate3; 


//메소드 참조


delegate0 = new  typeA(funcA);


delegate1 = new  typeB(funcB);


delegate2 = new  typeC(funcC);


delegate3 = new  typeD(funcD); 


이제 이러한 지식을 가지고 책의 예제 코드를 살펴보자.

using System;

namespace Delegate
{
    delegate int MyDelegate( int a, int b);

    class Calculator
    {
        public int Plus(int a, int b)
        {
            return a + b;
        }

        public static int Minus(int a, int b)
        {
            return a - b;
        }
    }

    class MainApp
    {
        static void Main(string[] args)
        {
            Calculator Calc = new Calculator();
            MyDelegate Callback;

            Callback = new MyDelegate( Calc.Plus );
            Console.WriteLine(Callback(34));

            Callback = new MyDelegate(Calculator.Minus);
            Console.WriteLine(Callback(75));
        }
    }
}


1. 우선 그 메소드와 동일한 타입의 델리게이트 타입을 선언해야 한다.

-> delegate int MyDelegate( int a, int b);


2. 그리고 선언한 델리게이트 타입으로 델리게이트 변수를 생성하고, 생성한 델리게이트 변수에 해당 메소드를 참조시킨다.

-> MyDelegate Callback;


    Callback = new MyDelegate( Calc.Plus );


이제 델리게이트가 plus() 메소드의 대리인으로써 수행할 권한이 생겼다.

-> Console.WriteLine(Callback(34));


이런식으로 델리게이트를 사용한다고 한다. 하지만 이렇게만 봐서는 "델리게이트를 저렇게 왜 써? 그냥 plus 메소드 불러가지고 쓰는거랑 같은거 아닌가? 장난하나"

라고 생각할 수 있는 예제이다. 

확실히 직접 메소드를 호출하면 되지 굳이 델리게이트로 참조해서 쓸 필요성이 전혀 없는 예제 이기 때문이다.


델리게이트의 진정한 가치는 콜백메서드 를 구현할 때에 나타난다고 한다.


콜백(Callback)이란, A라는 메소드를 호출할 때에 B라는 메소드를 넘겨주어

A메소드로 하여금 B 메소드를 호출하도록 하는 것을 말한다.



이 과정에서 델리게이트는 B메소드를 참조하는 변수로써 A메소드에게 넘겨지는 매개변수가 되고,

A메소드는 매개변수로 받은 델리게이트로 B메소드를 호출한다.


코드가 살짝 복잡해 보일 수 있지만, 실상 파악하고 나면 매우 간단한 코드이다.

계산기 함수를 따로 정적으로 구현 후, 매개변수로써 int a, int b (이들이 직접적으로 계산에 관여되는 애들), MyDelegate dele 이 바로 무슨 계산을 할 것이냐? 로 써 메소드를 참조하며 메소드를 보내주는 역활을 한다.

아주 간단한 코드 이므로 전혀 모르는 분들도 5분정도 뚫어지게 보다보면 아! 라는 감탄어가 나올 듯 하다.


windowform 으로 작업한 계산기는 아직 만들지 못했다.. 정확히 아직 어떤식으로 구현해야 하는지를 모르겠다 ㅜㅜ



c++


CAR class 멤버 함수 나머지 2개 남은 것을 손본다.

1.

void CAR::operator += (const CAR &T)      //1 안 -> 아래 코드처럼 cptemp 포인터로 사이즈를 두개의 카 cName 을 + 시킨다음
{                                          //       null을 위한 + 1 을 해준다.
  this->iColor = this->iColor + T.iColor; //2 안 -> realloc 으로 사이즈를 재 정의 해준다. (X)  1 안으로 실행. 
  this->iSpeed = this->iSpeed + T.iSpeed; 
  char *cpTemp = new char[strlen(this->cName) + strlen(T.cName) + 1];

  strcpy(cpTemp, this->cName);
  strcat(cpTemp, T.cName);

  delete[] cName;

  cName = cpTemp;
#ifdef DEBUG
  cout << cName << endl;
#endif //DEBUG
  return;
}


2.
void CAR::Print(ostream *T) const//iostream -> istream + osteram ( car1.print(&cout); ) 처럼 코드를 구현할 예정.
{                  //우리는 현재 cout << car3; 가능하도록 구현하려 한다.
  *T << "CAR {" << this->iColor << ", " << this->iSpeed << ", " << this->cName << "}";

  return;
}
//cout << 3 << 4 << 5 << endl
/*
cout 도 객체기 때문에 객체 << 객체 의 형태로써, cout의 객체에 operator << 라는 연산자가 오버로딩 되어 있어야 하는데
정의 되어 있지 않다. std의 ostream 클래스에도 쉬프트 연산에 대한 오버로딩이 정의 되어 있지 않다.
즉, 현재 멤버 함수로의 오버로딩으로는 객체를 출력할 수 없다 라는 것을 알고 있으므로 이것을 우리가 직접 정의하여 구현해야 한다.
전역함수로 정의 해보자.
연산자 operator << 는 인자값을 (cout, car3) 값으로 받고 실행하게 된다.
*/

ostream & operator << (ostream &O, CAR &T)  //cout 같은 애들을 반환해야 하기에 반환형이 ostream, 복사형을 반환해야하기에 + & 참조형
{
  T.Print(&O);  

  return O;
}





3.
#include <iostream>

using namespace std;

class smart
{
  private :

  public :



};

int main(void)
{
  char cNum;
  int iNum = 0;
  float fNum = 0.0;
  /* -> 숫자 입력 => 숫자 출력 , 문자 입력 => 문자 출력
     -> (int)로 캐스팅 후, 문자 입력 => 아스키 코드 값 출력
  cin >> cNum;
  cout << cNum << endl;
  */

  /* -> 문자 입력 => 0 값 출력
  cin >> fNum;
  cout << fNum << endl;
  */


  char buf[200];

  cin >> buf;
  cin >> buf;
  cout << buf << endl;
  
  return 0;
}












#include <iostream>
//상속
using namespace std;

class CAR
{
  private :


  public :
    CAR()
    {
      cout << "CAR Class 가 생성 되었습니다.\n";
    }

    ~CAR()
    {
      cout << "CAR Class 가 소멸 되었습니다.\n";
    }
};

class BMW : CAR
{
  private :

  public :
    BMW()
    {
      cout << "BMW Class 가 생성 되었습니다.\n";
    }

    ~BMW()
    {
      cout << "BMW Class 가 소멸 되었습니다.\n";
    }
};

int main(void)
{
  BMW obj1;  //부모가 있어야 자식이 있다! CAR 클래스 먼저 생성 후 BMW 클래스 생성.

  return 0;
}


728x90