[ 정    리 ]


 


오버로딩(Overloading) - 함수 중복 정의


오버로딩은 같은 이름의 함수에 매개변수를 다르게 사용하여 매개 변수에 따라 다른 함수가 실행되는 것.


 


오버라이딩(Overriding) - 함수 재정의

오버라이딩은 상속받았을때 부모클래스의 함수를 사용하지 않고 다른 기능을 실행할때 함수를 자식클래스에 같은 이름, 매개변수로 재정의 해서 사용하는 것.


 


※ 자세한 내용은 아래 설명 참조.


 


 


 


===========================================================================================


 



* 오버로딩(Overloading)


 


 특징 :

1. 메소드 이름이 같아야 한다.

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

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

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


 


객체 지향 프로그래밍에서 오버로딩(Overloading)은 같은 이름의 메소드를 여러개 중복 선언하는 것을 말합니다.

C와 같은 기존 언어에서는 같은 이름의 함수를 만들 수 없었습니다.  이것이 직관적으로 보일 수 있지만, 다음과 같은 경우를 보면 생각이 달라질 것입니다.


만약, 정수값들을 더해서 평균을 내는 메소드를 만들어서 사용하고 있다고 합시다.  이걸 사용하다 보니 같은 기능을 하는 것으로서 실수를 다루는 메소드를 만들고 싶다면 어떻게 할까요.  예를 들어, 정수를 위한 메소드 이름이 averge() 이었다면, 실수를 다루는 것은 조금이라도 이름이 달라야 하기 때문에 average_float()과 같은 식으로 작성해야 할 것입니다.


 


하지만, 이런식으로 메소드들이 수없이 만들어지면 개발자는 모든 함수를 기억하기가 힘들어질 것입니다.  이 경우 둘다 평균을 구하는 것이기 때문에 averge()라는 이름으로 사용하면 좋을것인데 말입니다.  C#에서는 이런 경우 average()라는 이름을 같이 사용할 수 있도록 하고 있습니다.


즉, 정수를 인수로 받는 average()메소드와 실수를 인수로 받는 average() 메소드를 같이 정의할 수 있게 하는 것입니다.


average()루틴을 사용하는 측면에서는 어떻게 각각을 구별할까요?

구별은 의외로 간단합니다.  단지, average() 메소드에 넘기는 인수의 종류를 달리해주면 됩니다.  정수를 다루는 average()를 부르고 싶다면, average() 인수에 정수값들만 넘기면 됩니다.  만약, 실수를 다루는 경우에는 average() 인수로 실수값들만 넘기면 내부적으로 적절한 메소드가 수행되도록 해줍니다.



 


 


[샘플 소스 - 평균값 구하기(정수/실수)]


// 정수타입(1, 2, 3) 변수 a, b를 이용하여 평균값을 계산하는 함수

void average(int a, int b)


{


int avg = 0;


avg = (a * b) / 2;


printf(정수값 %d와 %d의 평균은 %d 입니다.\n", a, b, avg);


}


 


// 실수타입(1.5, 2.3, 3.1) 변수 a, b를 이용하여 평균값을 계산하는 함수


void average(float a, float b)


{


float avg = 0;


avg = (a * b) / 2;


printf(실수값 %f와 %f의 평균은 %f 입니다.\n", a, b, avg);


}


 


훨씬 직관적인 프로그램을 할 수 있는 것입니다.

오버로딩을 위해서는 몇가지 지켜야 할 것이 있습니다.  avg()라는 똑같은 이름을 사용할 수 있다고 했지만, 각각을 구별할 수 있는 방법이 필요합니다.  C#에서는 각 메소드에 대해서 시그네이쳐를 형성해서 이들을 구별합니다.  시그네이쳐는 각 메소드의 이름과 인수의 종류, 인수의 갯수에 구별됩니다.

따라서, 인수의 갯수나 타입만 다르다면 같은 이름의 메소드라도 몇개든지 선언할 수 있는 것입니다.  하지만, 반환타입은 시그네이처에 포함되지 않기 때문에 주의해야 합니다.  반환값만 다른 경우에는 컴파일러가 에러를 발생시킬 것입니다.



 


 


 


===========================================================================================


 


 


* 오버라이딩(Overriding)


 


특징 : 

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

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

3. 메소드 파라미터 개수, 파라미터의 자료형이 같아야 한다.

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

5. 상위 메소드와 동일하거나 내용이 추가되어야 한다.



오버라이딩(overriding)은 상속 관계간에 발생합니다.  기본적인 생각은 부모 클래스에 정의된 메소드와 똑같은 시그네이쳐를 같는 메소드를 자식 클래스에서 정의해서 부모 클래스의 내용이 보이지 않게 하자는 것입니다.

이를 통해, 상속 받은 내용중 일부를 변경해서 사용하는 것이 가능해 집니다.  오버라이딩을 위해서는 부모 클래스에서 정의된 내용과 똑같은 이름과 인수 구성을 가져야 한다는 점을 명심하시기 바랍니다.

오버로딩의 경우에는 인수가 달라야 한다는 점을 빼면 특별히 해주어야 하는 부분이 없었습니다.  하지만, C#에서 오버라이딩을 구현하기 위해서는 virtual, override, new와 같은 몇가지 기능을 사용해야 합니다.


만약, 이러한 키워드를 사용하지 않은체로 프로그램을 작성할 경우 원하는 형태대로 작동하지 않을 수 도 있습니다.


먼저, 오버라이딩이 되도록 하려는 부모 클래스의 메소드 앞에 virtual이라는 키워드를 붙여 줍니다. 이렇게 한후 자식 클래스에서는 override 키워드를 사용해서 오버라이딩을 한다는 것을 알려줘야 합니다.  이렇게 하지 않고 그냥 사용할 경우 다형성을 다루는 프로그램에서 문제가 발생합니다.


또한, 부모에 정의된 것을 대체하는 메소드로 오버라이딩하고자 하는 경우 new연산자를 사용합니다.

new 연산자를 사용하면, 그 위 부모는 전혀 보이지 않게 됩니다.  심지어 다형성 프로그램에서도요...


virtual 로 선언된 가상 메소드는 메소드 상속 구조 상에서 제일 위에 있는 메소드로 구분되어집니다.  따라서, 그 위 부모에 똑같은 메소드가 있다 하더라도 마지막 virtual 키워드 다음의 내용만이 살펴 보게 됩니다.


만약, 오버라이딩된 메소드에서 새로운 형태로 쓰일 메소드를 정의하고자 한다면 new 키워드를 사용해야 합니다. 즉, 다형성 프로그램에서 부모 클래스에 정의되어 있는 오버라이딩된 메소드가 전혀 보이지 않게 할 수 있습니다.

만약, 새로 메소드를 재정의하면서 가상으로 선언하고 싶다면 new virtual 키워드를 연속으로 사용하면 됩니다.


 


 


[샘플 소스]


#include <stdio.h>


class Parent

{

    public:

        void outA(int a)

        {

            printf("%d\n",a);

        }

    };


    


class Child: public Parent

{

    public:

        void outA(int a)

        {

            printf("%d\n",a+a);

        }

    };



void main()

{

    Child a;

    Parent b;

    a.outA(10);

    b.outA(10);

}


}


}




// 결과 

//10

//20


 


 


 


===========================================================================================


 


 


* 다형성(Polymorphism)


다형성은 오버라이딩과 밀접한 연관이 있는 객체 지향 프로그래밍의 특징중 하나입니다.

다형성이라는 말 자체는 같은 메소드를 호출할 때 실제 수행되는 내용은 객체가 무엇이냐에 따라 달라진다는 얘기입니다.

예를 들어, 그림을 그리고자 할 때, 삼각형 객체에게 Draw()하는 것과 사각형 객체에게 Draw()하는 것은 모두 Draw()라는 루틴을 통해 그림을 그리게 하는 것이지만, 삼각형이 그리는 그림과 사각형이 그리는 그림은 다르게 된다는 것입니다.

즉, 똑같은 방식으로 호출하지만 실제 수행은 다르게 나타나는 것을 다형성이라고 합니다.


삼각형 객체와 사각형 객체에 대해서 다형성 기능을 구현하기 위해서는 둘다 같은 부모를 상속 받아야 합니다.

예를 들어, 다음과 같은 형태가 다형성을 이용한 경우입니다.


 


 


[샘플 소스]


class Shape {

  public void Draw() { }

}


class Triangle : Shape {

  public void Draw() { System.Console.WriteLine("Draw Triangle"); }

}




class Rectangle : Shape {

  public void Draw() { System.Console.WriteLine("Draw Rectangle"); }

}




class Test {

  static void Main()

  {

    Shape a[] = new Shape[2];

    a[0] = new Triangle();

    a[1] = new Rectangle();

    

    for (int i = 0; i < a.Length; i++)

      a[i].Draw();


}


이 경우 Shape를 상속 받은 클래스들을 만든 후 실제 객체를 생성할 때에는 그 내용을 Shape 배열에 대입하고 있습니다.  이것은 자식을 부모에 대입하는 형태인데, 대입이 가능합니다(앞의 상속 부분을 생각해 보세요. ;)


하지만, 위 코드를 그대로 사용하면 문제가 있습니다.  각각 만들어진 객체의 Draw()가 불리지 않고 Shape의 Draw()가 불리는 것입니다.

이를 해결하기 위해서는 Shape의 Draw()에 virtual 키워드를 붙이고, 각각 오버라이드한 메소드에서는 override 키워드를 붙여야 합니다.  그렇게 하면 정상적으로 다형성 예를 볼 수 있을 겁니다.


 

ref: http://memoryfilm.tistory.com/16 [린월의 Memory Film]

'Programming > C,C++' 카테고리의 다른 글

c++ new delete overriding / leak checker  (0) 2017.04.03
상속과 virtual함수 [펌]  (0) 2017.03.27
STL vector, list, map [펌]  (0) 2017.03.24
echo server/client  (0) 2017.03.24
visual studio 2015 error:4996  (0) 2017.03.23
Posted by 루나s
,