관리 메뉴

드럼치는 프로그래머

[C/C++] 오버로딩과 오버라이딩!!! 본문

★─Programing/☆─C | C++

[C/C++] 오버로딩과 오버라이딩!!!

드럼치는한동이 2011. 11. 3. 15:26
아 개념이 완전히 잡혔었다 생각했었는데

 역시 군대가서 머리가 포맷된듯...

 그것도 로우레벨 포맷 3회로!!!!!!!

 

 아무튼 오버로딩과 오버라이딩의 차이점을 알아보자...

 

 - 오버로딩 : 기존에 메소드의 인자를 이용하여서 하나의 함수에 여러가지 기능을 만드는것.

 (어렵다..... 젠장 말이 어렵다 어려워~)

 

 기존에 int a(int a);라는 함수와

 또다른 int a(int a, char b)가 존재한다고 가정한다.

 

 main()에서 호출시 a(10); 이라고 호출하게 되면 첫번째 int a(int a)라는 함수가 호출된다.

 만약 a(10,'x'); 를 호출했다면 후자인 int a(int a,char b)가 호출되게 된다.

 ( 이것이 오버로딩!!!!!!!!)

 

 이것은 주로 생성자 메소드를 정의할 때 많이 사용한다. 한마디로 같은 함수의 이름을 가지지만 인자 갯수나 타입으로 구분해서 사용하는 것이다.

 

 - 객체지향 개념에서 오버로딩 만큼이나 중요하면서 상속 개념에서 빼 놓을 수 없는 것이 바로 오버라이딩이다!!!(나도 안다 이건 ㅠㅠ)

 오버라이딩이란 상위 클래스에 있는 메소드와 똑같은 메소드를 하위 클래스에서 다시 만드는 행위를 말합니다. 즉 하위클래스에서 메소드를 재정의하는 행위를 말한다!!!!!!!(이게 뽀인트!!)

 

 메소드 재정의(Overriding)를 누군가는 "아버지 무시하기(?)" 라고 하신단다;;;(이해가 쉽군!!)

 - 이유는 아들이 아버지의 메소드를 재정의 했을때 아버지의 메소드를 완전히 무시하는 경향이 있기 때문이다..

 

- 상속 개념에서의 오버라이딩(overriding)

 : 아버지 클래스를 상속받아 아들 클래스를 만들었을 때, 아버지가 가지고 있던 메소드를 아들 클래스가 다시 만들었다고 가정해보자. 아버지 것은 내것이고 내것도 내것이니 완벽하게 똑같은 이름의 메소드가 두개 존재한다. 아들 클래스의 객체변수를 만들고 이 객체를 이용해서 메소드를 호출한다면 아들 클래스는 순간 당황하게 될 수도 있겠다... 아버지 것을 사용할까? 내것을 사용할까? 하지만 아들은 과감히 아버지것을 무시하고 아들의 것을 사용한다. 왜냐!!!! "내가 더 소중하니까요!!!"(명언이다!!) 이것이 오버라이딩(overriding)이다!!!!

 

------------------------------------------------------------------------------------------

 

여기서 virtual 키워드를 왜!!!! 사용하는지에 대한 해답이 나오는 것이다.

virtual키워드를 사용함으로써 나는 부모 메소드를 사용하는 것이 아니고 새로 정의한 메소드를 사용하겠다고 선언하는 것이다!

 

굳이 virtual키워드를 붙이지 않아도 컴파일 되는 과정에서 자동으로 분류 해주기는 하나 명확히 구분하기 위해서 virtual키워드를 붙이는 것이다...(결국 가독성을 위한것이군!!!)

 

------------------------------------------------------------------------------------------

 

각각의 특징을 살펴보면..(뉘집 자식인지 정리 잘해놓으셔따 ㅠㅠ)

 

* 오버로딩 : 1. 메소드 이름이 같아야한다

                 2. 리턴형이 같아도 되고 달라도 된다

                 3. 파라미터의 개수가 달라야 한다

                 4. 파라미터 개수가 같을경우 자료형이 달라야한다.

                 5. 같은 클래스의 블록안에 지원된다.

 

* 오버라이드 : 1. 오버라이드 하고자 하는 메소드가 상위 클래스에 존재해야 한다.

                    2. 메소드의 이름이 같아야한다.

                    3. 메소드의 파라미터 개수와 데이터형이 같아야 한다.

                    4. 메소드의 리턴형이 같아야 한다.

                    5. 상위 메소드와 동일하거나 더 구체적인 Exception을 발생시켜야 한다.

                    6. 상위 메소드와 동일하거나 접근 범위가 넓은 접근 제한자를 사용해야 한다.

 

오버로딩 : 새로 만든다는 개념

오버라이딩 : 기존에 있는 메소드를 재정의 한다는 개념

------------------------------------------------------------------------------------------

아래는 간단한 오버로딩의 예제소스.

 

class CPPTestLoading
{
public:
 CTestLoading()
 {
 }
 ~CTestLoading()
 {
 }

 void Set(int _a,int _b)
 {
  a = _a;
  b = _b;
  c = 0;
 }
 void Set(int _a,int _b,int _c)
 {
  a = _a;
  b = _b;
  c = _c;
 }

 int a;
 int b;
 int c;
};

void main()
{
 CPPTestLoading obj;

 obj.Set(1,2);
 obj.Set(1,2,3);
}


위의 소스에서처럼 오버로딩을 하면 같은 함수명을 사용하기에 편한것처럼
보이지만 오버로딩을 많이 하면 성능의 저하가 일어날 수 있단다...(왜?)
오버로딩을 c언어로 구현을 해보면 금방 알 수가 있다..


typedef struct CTestLoading
{
 int a;
 int b;
 int c;
}CTestLoading;

void CTestLoading_Set_1(CTestLoading* obj,int _a,int _b)
{
 obj->a = _a;
 obj->b = _b;
 obj->c = 0;
}
void CTestLoading_Set_2(CTestLoading* obj,int _a,int _b,int _c)
{
 obj->a = _a;
 obj->b = _b;
 obj->c = _c;
}

void main()
{
 CTestLoading obj;

 if(매개변수갯수 == 2 && 자료형이 모두 int형이라면)
  CTestLoading_Set_1(&obj,1,2);
 else if(매개변수갯수 == 3 && 자료형이 모두 int형이라면)
  CTestLoading_Set_2(&obj,1,2,3);
}


위의 소스처럼 오버로딩의 갯수가 많아질수록 if - else if문이 늘어나게
되어 성능이 저하될 수가 있다...(정답이로구나!!!)
c++에서는 이 과정을 프로그래머에게 보여주지 않고 숨긴다는데... 흠.... 음흉하구먼 ㅋㅋ


아래는 간단한 오버라이딩 예제

class CPPTestRiding
{
public:
 CPPTestRiding()
 {
 }
 virtual ~CPPTestRiding()
 {
 }

 virtual void Set(int _a,int _b)
 {
  a = _a;
  b = _b;
 }

 int a;
 int b;
};

class CPPTestRidingChild : public CPPTestRiding
{
public:
 CPPTestRidingChild()
 {
 }
 virtual ~CPPTestRidingChild()
 {
 }

 virtual void Set(int _a,int _b)
 {
  a = _a + 10;
  b = _b + 10;
 }
};

void main()
{
 CPPTestRiding *obj = new CPPTestRidingChild;

 obj->Set(10,10);
 printf("%d %d",obj->a,obj->b);

 delete obj;
}

실행해보시면 main에서의 Set은 Child클래스것을 사용했음을 알 수 있다..
그럼 저것을 c언어로 바꾸어서 표현을 해보죠..
(참고로 원래는 malloc과 free를 써야되지만 그냥 new와 delete를 썼음..)

 

typedef void (*Set)(void* obj,int _a,int _b);  // 가상함수의 타입을 정의함..

typedef struct CTestRiding
{
 int a;
 int b;
 Set SetFunc;                 // c++에서의 가상함수
}CTestRiding;


void CTestRiding_Set(void* obj,int _a,int _b)
{
 CTestRiding* castObj = (CTestRiding*)obj;

 castObj->a = _a;
 castObj->b = _b;
}

CTestRiding* CTestRiding_Create()
{
 CTestRiding *obj;

 obj = new CTestRiding;
 obj->SetFunc = CTestRiding_Set;   // 이부분에서 해당객체의 메소드를 재정의함..

 return obj;
}


typedef struct CTestRidingChild
{
 CTestRiding parent;              // 상속을 표현..
}CTestRidingChild;

void CTestRidingChild_Set(void* obj,int _a,int _b)
{
 CTestRidingChild* castObj = (CTestRidingChild*)obj;

 castObj->parent.a = _a + 10;
 castObj->parent.b = _b + 10;
}

CTestRiding* CTestRidingChild_Create()
{
 CTestRidingChild *obj;

 obj = new CTestRidingChild;
 obj->parent.SetFunc = CTestRidingChild_Set;   // 이부분에서 해당객체의 메소드를 재정의함..

 return ((CTestRiding*)obj);
}

void main()
{
 CTestRiding* obj = CTestRidingChild_Create();

 obj->SetFunc(obj,10,10);

 printf("%d %d\n",obj->a,obj->b);

 delete obj;

}

 

위의 소스를 보면 함수 포인터를 이용하여 가상함수를 구현하고 있다.

객체를 Create할때 내부적으로 정의된 함수로 세팅을 하게 되는것이다..

 

 

출처 : http://www.samsiki.net/115 인데... 이분도 출처가 있다..

(http://kin.naver.com/db/detail.php?d1id=1&dir_id=10104&eid=DnIPq0ZiUVofjYysZnP+kKJOjwjdYB7t&qb=v8C59rfOtfkgv8C59rbzwMy1)

더블출처!!!!!


Comments