다형성(Polymorphism)은 객체 지향 프로그래밍의 핵심 개념 중 하나로, 하나의 인터페이스나 메서드 이름이 상황에 따라 여러 가지 형태로 동작할 수 있도록 하는 기능입니다. C#에서 다형성은 크게 정적(Static) 다형성과 동적(Dynamic) 다형성 두 가지로 나뉩니다.
정적 다형성에서는 함수에 대한 응답이 컴파일 시점에 결정되는 반면, 동적 다형성에서는 런타임(실행) 시점에 결정됩니다. 이러한 동적 다형성을 우리는 흔히 '늦은 바인딩(Late Binding)'이라고 부릅니다.
컴파일 타임 다형성 (정적 바인딩)
컴파일 시점에 함수와 객체를 연결하는 메커니즘을 초기 바인딩(Early Binding)이라고 하며, 이를 정적 바인딩(Static Binding)이라고도 합니다. 대표적인 예로 메서드 오버로딩(Method Overloading)이 있습니다. 같은 이름의 메서드라도 매개변수의 개수나 자료형이 다르면, 컴파일러가 호출 시점에 어떤 메서드를 실행할지 미리 판단합니다.
런타임 다형성 (동적 바인딩)
런타임 다형성은 메서드 오버라이딩(Method Overriding)을 통해 구현되며, 동적 바인딩(Dynamic Binding) 또는 늦은 바인딩(Late Binding)이라고도 불립니다. 부모 클래스의 참조 변수가 자식 클래스의 객체를 가리킬 때, 실제 실행될 메서드는 프로그램이 실행되는 도중에 결정됩니다.
예제: 컴파일 타임 다형성 (메서드 오버로딩)
다음은 메서드 오버로딩을 활용해 컴파일 타임 다형성을 구현한 C# 코드 예제입니다. 동일한 이름의 print() 메서드가 매개변수의 자료형에 따라 각각 다르게 동작하는 것을 확인할 수 있습니다.
using System;
namespace PolymorphismApplication {
class Printdata {
void print(int i) {
Console.WriteLine("Printing int: {0}", i);
}
void print(double f) {
Console.WriteLine("Printing float: {0}", f);
}
void print(string s) {
Console.WriteLine("Printing string: {0}", s);
}
static void Main(string[] args) {
Printdata p = new Printdata();
// 정수 출력을 위한 print 호출
p.print(5);
// 실수(float) 출력을 위한 print 호출
p.print(500.263);
// 문자열 출력을 위한 print 호출
p.print("Hello C#");
Console.ReadKey();
}
}
}실행 결과
Printing int: 5 Printing float: 500.263 Printing string: Hello C#
핵심 정리
- 정적 다형성(컴파일 타임): 메서드 오버로딩으로 구현되며, 컴파일 시점에 호출 대상이 결정됩니다.
- 동적 다형성(런타임): 메서드 오버라이딩으로 구현되며, 실행 시점에 호출 대상이 결정됩니다.
다형성을 잘 활용하면 코드의 유연성과 재사용성이 크게 향상되므로, 두 방식의 차이를 명확히 이해해 두는 것이 좋습니다.