본문 바로가기
코스웨어/10년 시스템제어

시스템 제어 일일 보고서 - 김진웅 (7번)

by 알 수 없는 사용자 2010. 5. 19.
728x90
반응형



★const 멤버 함수
 
#include <iostream>

using namespace std;


class Who
{
  public:
    void test() const 
    {
      cout << "test...\n";
    }
};

int main()
{
  Who Obj1;
  Obj1.test();

  return 0;
}

위와같이 부르게되면 일반함수와 똑같다. 그렇다면 무슨 차이가 있을까?
 
 
class Who
{
  public:
    int i;
    Who()
    {
      i = 9;
    }
    void test() const 
    {
      cout << "test...\n";
      i = 10
      cout << "i = " << i << endl;
    }
};

클래스의 내용을 위와같이 만들어보았다. 그러나 아래그림과같이 에러가 뜬다.

이렇게 다른 곳의 변수를 바꾸지 못한다.

그렇다면 인자를 받으면 어떻게 될까?

 
class Who
{
  public:
    int i;
    Who()
    {
      i = 9;
    }
    void test(int iNum) const 
    {
      cout << "test...\n";
      //i = 10;  //안에서 변경이 불가능하다. // const 함수 속성 위반, 컴파일불가.
      iNum = 0;//인자로 들어온 값은 변경이 가능하다.
      cout << "i = " << i << endl;
      cout << "iNum = " << iNum << endl;

    }
};
int main()
{
  Who Obj1;
  Obj1.test(1);  

  return 0;
}


위와같이 인자로 받을경우 컴파일이 잘된다. 즉, 인자로 받은함수는 변수로하되, 다른곳의 변수들은 상수화시킨다는것을 알수있다.



 그리고 c++ 에선 특이한것이 있는데. 바로 this 이다. this가 뭐냐고 하면..

 

class Who
{
  public:
    int i;
    Who()
    {
      i = 9;
    }
    void test(int iNum) const 
    {
      cout << "test...\n";
      //i = 10;  //안에서 변경이 불가능하다. // const 함수 속성 위반, 컴파일불가.
      iNum = 0;//인자로 들어온 값은 변경이 가능하다.
      cout << "i = " << i << endl;
      cout << "iNum = " << iNum << endl;
      cout << this << endl; // c++에서 this를 쓰게되면,
         //자기자신을 가르키는 클래스 포인터라고 생각할수있다.
    }
};

int main()
{

  Who Obj1;
  Obj1.test(1);

  return 0;
}


위와같이 하게되면 아래그림과같이 자기 클래스의 주소를 가르킨다.





클래스 안의 static함수에 대해 알아보자.

 

class Who
{
  public:
    int i;
    Who()
    {
      i = 9;
    }
    void test(int iNum) const 
    {
       - 생략 -

    }
    static void testStatic()
    {
      cout << "testStatic\n";
    }
};

int main()
{
  //testStatic()을 호출해 
  Who::testStatic(); //스태틱 함수는 클래스객체 없이도 선언된다.

/*  
  Who Obj1;
  Obj1.test(1);
  Obj1.testStatic();

  cout << &Obj1 << endl;
*/
  
  return 0;
}


위와같이 클래스 객체 없이도 선언이 된다.
그렇다면 아까본 this를 여기서 사용하면 어떻게 될까?

 
static void testStatic()
{
  cout << "testStatic\n";
  cout << this << endl;
}

int main()
{
  //testStatic()을 호출해 
  Who::testStatic(); //스태틱 함수는 클래스선언 없이도 선언된다.

  return 0;
}


위와같이 스태틱함수안에 this를 넣으면 그림과같이 에러가 뜬다.

왜 이런것일까? 객체가 없어서 그런것일까?? 그렇다면 객체를 만들어보겠다.

 
class Who
{
  public:
    int i;
    Who()
    {
      i = 9;
    }
    void test(int iNum) const 
    {
      //생략                     }
    static void testStatic()
    {
      cout << "testStatic\n";
      cout << this << endl;
    }
};

int main()
{
  //testStatic()을 호출해 
  //Who::testStatic(); //스태틱 함수는 클래스선언 없이도 선언된다.

  Who Obj1;
  Obj1.test(1);
  Obj1.testStatic();

  cout << &Obj1 << endl;

  return 0;
}


이렇게해도 역시 에러가 뜬다. 왜 이렇게 에러가뜨는거냐 하면..

static함수는 객체생성을 떠나서, 이미 먼저 만들어지기 떄문에 컴파일러에서 에러를 뛰운다.


★class  - virtual 사용방법 숙지

도형을 그린다고 가정하고 아래와같이 소스를 짠다고 하자.

 
#include <iostream>

using namespace std;

class shape
{
  public:
    void draw()
    {
      cout << "shape::draw()\n";
    }
};

class rectangle: public shape
{
  public:
    void draw()
    {
      cout << "ractangle::draw()\n";
    }
};
class circle: public shape
{
  public:
    void draw()
    {
      cout << "circle::draw()\n";
    }
};

int main()
{
  shape  * cpshape = new shape;
  rectangle  * cprectangle = new rectangle;
  circle  * cpcircle = new circle;

  cpshape    -> draw();
  cprectangle  -> draw();
  cpcircle    -> draw();

  return 0;
}

위와같이하게 되면 그림과같이 순서대로 출력된다.

도형을 그리는대 도형이라는 부분이 필요할까?
당연히 필요없다. 도형은 그저 원,사각형,삼각형.. 등을 포함하고 있을뿐, 출력될 필요는 없다.
그렇다면, 이부분을 출력하지 않게 하기위해서는 아래와같이.

 
class shape
{
  protected:
    shape(){}//이렇게하면 절때생성할수업다.
  public:
    virtual void draw()
    {
      cout << "shape::draw()\n";
      cout << "이건 추상적인 부분이기에 호출되면 부적당....\n";
    }
};
위와같이 생성자에 protected해주면 생성이 되지 않는다.
그리고, 도형의 draw함수는 부를 필요가 없기떄문에 virtual 로 해주면 아래그림과같이 필요한부분만 됨을 알수있다.


그리고 이렇게 된다면, 아래 소스와같이 간단하게 정리도 된다.
 
int main()
{
  circle ObjCircle;
  rectangle ObjRect;

  //객체 기반 호출.
  shape    *  cpShape1  = &ObjCircle; 
  shape    *  cpShape2  = &ObjRect;
  
  cpShape1  -> draw();
  cpShape2  -> draw();
  
  return 0;
}
이런식으로 부모의 클래스로 포인터를 생성하여 가르키게되면, 모든 클래스를 제어할수 있게되며,
보는사람도 편하거니와, 정리도 깔끔하게 된다.
이런방식을 객체 기반 호출 이라고한다.

그런데 이것에는 문제가있다. 어떤 문제냐하면...
동적할당을 받어보자.

 
class shape
{
  protected:
    shape(){}//이렇게하면 절때생성할수업다.
  public:
    ~shape()
    {
      cout << "shpae 소멸자\n";
    }
};

class rectangle: public shape
{
  public:
    ~rectangle()
    {
      cout << "rectangle 소멸자\n";
    }
};
class circle: public shape
{
  public:
    ~circle()
    {
      cout << "circle 소멸자\n";
    }
};

int main()
{
  circle ObjCircle;
  rectangle ObjRect;

  shape    *  cpShape1  = new circle; 
  shape    *  cpShape2  = new rectangle;
  
  delete cpShape1;
  delete cpShape2;
  

  return 0;
}


이렇게하면 아래그림과같이 일반적으로 객체를 선언했을때와, 동적할당을 했을때, 생성되는 소멸자가 다르다.
여기서 문제 점이 무엇이냐면, 위의 그림같은경우, circle 클래스가 만들어지며, 소멸할떄 둘이 같이 소멸한다.
하지만, 동적할당을 할 경우, 안의 함수호출은 되지만, circle 클래스의 소멸자가 뜨지가 않는다.
이 문제를 해결하기 위해서는.... 앞에서 하였던것 처럼 virtual을 해주게 되면 해결되게 된다.

 
class shape
{
  protected:
    shape(){}//이렇게하면 절때생성할수업다.
  public:
    virtual void draw()
    {
      cout << "shape::draw()\n";
      cout << "이건 추상적인 부분이기에 호출되면 부적당....\n";
    }
    virtual ~shape()
    {
      cout << "shpae 소멸자\n";
    }
};

위와같이 하게되면 정상적으로 작동됨을 알수있다.

이렇게 동적할당을 받을경우, 좋은점이 무엇이 있을까? 아래소스를 보자.

 
int main()
{
  
shape    *  cpShape1  = new circle;
  shape    *  cpShape2  = new rectangle;

  cpShape1  -> draw();
  // 동적 바인딩 이라고하며 동적할당을 받어서 사용하게되면
  // 실행되기전에 주소를 받고 없어지기 떄문에,

  // disassemble이 거의 불가능하다.
  // 보안적으로 좋기때문에 사용한다.

  cpShape2  -> draw();  

  delete cpShape1;
  delete cpShape2;

  return 0;
}


여기서 한가지더 문제점이 있다. 무슨 문제점이냐고 하면..

 
class triangle: public shape
{
  public:

    ~triangle()
    {
      cout << "triangle 소멸자\n";
    }
};

위와같이 실수로 draw를 없이 소멸자만 만들었다고 치자.
그렇게 된다면 아래그림과 같이 shape의 draw함수가 호출된다.

draw함수가 호출되버렸다. 이렇게되면 분명 안되는것이다.
그렇다면 이문제를 어떻게 해결하면 될까?

해결법은 의외로 간단하다.

 
class shape
{
  protected:
    shape(){}//이렇게하면 절때생성할수업다.
  public:
    virtual void draw() = 0// 이 함수는 없지만 꼭만들어라고 강요한다.
    
/*{
      cout << "shape::draw()\n";
      cout << "이건 추상적인 부분이기에 호출되면 부적당....\n";
    }*/

    virtual ~shape()
    {
      cout << "shpae 소멸자\n";
    }
};


위와같이 함수 = 0; 이라고 해주게되면, 아래그림과같이 에러를 뛰우며 draw함수를 만들라고 강요를 하게된다.
하지만, 자기자신은 draw라는 함수가 존재하지 않는다.
(그림을 자세히 보고싶으면 그림을 클릭해 주쎄용~)

이렇게 에러를 뛰우며 이 부분을 고치게되면

 
class triangle: public shape
{
  public:
    void draw()
    {
      cout << "circle::draw()\n";
    }
    ~triangle()
    {
      cout << "triangle 소멸자\n";
    }
};

아래와 같이 잘 뜨게된다.




오탈자나 틀린부분 지적부탁드립니다 (__)

728x90