Computer >> 컴퓨터 >  >> 프로그래밍 >> C 프로그래밍

C++ 다형성의 4가지 유형 완벽 정리: 임시(Ad-Hoc), 포함(Inclusion), 매개변수(Parametric), 강제(Coercion)

다형성(Polymorphism)은 하나의 인터페이스나 함수가 여러 형태로 동작할 수 있게 해주는 객체지향 프로그래밍의 핵심 개념입니다. 다형성은 크게 다음과 같은 네 가지 유형으로 분류할 수 있습니다.

  • 임시 다형성 (Ad-Hoc Polymorphism)
  • 포함 다형성 (Inclusion Polymorphism)
  • 매개변수 다형성 (Parametric Polymorphism)
  • 강제 다형성 (Coercion Polymorphism)

각 유형의 특징과 C++ 코드 예제를 통해 자세히 살펴보겠습니다.

1. 임시 다형성 (Ad-Hoc) - 오버로딩

임시 다형성은 흔히 오버로딩(Overloading)이라고 불립니다. 같은 이름의 함수가 서로 다른 타입에 대해 서로 다른 방식으로 동작하도록 허용하는 기능입니다. 함수뿐만 아니라 연산자도 오버로딩할 수 있으며, 일부 언어에서는 연산자 오버로딩을 지원하지 않지만 함수 오버로딩은 대부분의 언어에서 널리 사용됩니다.

예제

#include<iostream>
using namespace std;
int add(int a, int b) {
    return a + b;
}
string add(string a, string b) {
    return a + b; // 문자열 연결
}
int main() {
    cout << "Addition of numbers: " << add(2, 7) << endl;
    cout << "Addition of Strings: " << add("hello", "World") << endl;
}

실행 결과

Addition of numbers: 9
Addition of Strings: helloWorld

위 예제처럼 add() 함수는 정수를 전달받으면 두 수를 더하고, 문자열을 전달받으면 두 문자열을 연결합니다. 컴파일러는 인자의 타입을 보고 적절한 함수를 선택합니다.

2. 포함 다형성 (Inclusion) - 서브타이핑

포함 다형성은 서브타이핑(Subtyping)이라고도 하며, 런타임 다형성(Runtime Polymorphism)에 해당합니다. 기반 클래스(Base Class)의 포인터나 참조를 사용하여 파생 클래스(Derived Class)의 객체를 가리킬 수 있는 기능입니다. 실제 객체의 타입은 프로그램이 실행되기 전까지는 알 수 없으며, C++에서는 가상 함수(virtual function)를 사용하여 이 포함 다형성을 구현합니다.

예제

#include<iostream>
using namespace std;
class Base {
    public:
        virtual void print() {
            cout << "This is base class." << endl;
        }
};
class Derived : public Base {
    public:
        void print() {
            cout << "This is derived class." << endl;
        }
};
int main() {
    Base *ob1;
    Base base_obj;
    Derived derived_obj;
    ob1 = &base_obj; // 기반 클래스 객체
    ob1->print();
    ob1 = &derived_obj; // 동일한 포인터로 파생 클래스 객체 지정
    ob1->print();
}

실행 결과

This is base class.
This is derived class.

같은 포인터 ob1이 실행 시점에 어떤 객체를 가리키느냐에 따라 호출되는 함수가 달라지는 것을 확인할 수 있습니다. 이것이 바로 런타임 다형성의 핵심입니다.

3. 강제 다형성 (Coercion) - 캐스팅

강제 다형성은 흔히 캐스팅(Casting)이라고 부릅니다. 객체나 원시 타입(primitive type)이 다른 타입으로 변환될 때 발생하는 다형성입니다. 캐스팅에는 두 가지 종류가 있습니다.

  • 암시적 캐스팅(Implicit Casting): 컴파일러가 자동으로 수행하는 형 변환
  • 명시적 캐스팅(Explicit Casting): const_cast, dynamic_cast, static_cast 등을 사용하여 개발자가 직접 지정하는 형 변환

예제

#include<iostream>
using namespace std;
class Integer {
    int val;
    public:
        Integer(int x) : val(x) {
        }
        operator int() const {
            return val;
        }
};
void display(int x) {
    cout << "Value is: " << x << endl;
}
int main() {
    Integer x = 50;
    display(100);
    display(x);
}

실행 결과

Value is: 100
Value is: 50

위 예제에서 Integer 클래스는 변환 연산자(operator int)를 통해 int 타입으로 자동 변환됩니다. 따라서 display(x)를 호출할 때 Integer 객체가 암시적으로 int 값으로 변환되어 전달됩니다.

4. 매개변수 다형성 (Parametric) - 템플릿

매개변수 다형성은 조기 바인딩(Early Binding)과 관련이 있습니다. 이 다형성은 동일한 코드 조각을 서로 다른 타입에 대해 재사용할 수 있도록 해주며, C++에서는 템플릿(Template)을 사용하여 구현합니다.

예제

#include<iostream>
using namespace std;
template <class T>
T maximum(T a, T b) {
    if(a > b) {
        return a;
    } else {
        return b;
    }
}
int main() {
    cout << "Max of (156, 78): " << maximum(156, 78) << endl;
    cout << "Max of (A, X): " << maximum('A', 'X') << endl;
}

실행 결과

Max of (156, 78): 156
Max of (A, X): X

위 예제의 maximum() 함수는 하나의 템플릿 정의만으로 정수와 문자 등 다양한 타입에 대해 동작합니다. 컴파일 시점에 각 타입에 맞는 함수가 생성되므로 성능 저하 없이 코드 재사용성을 극대화할 수 있습니다.

정리

다형성은 코드의 유연성과 재사용성을 높이는 중요한 개념입니다. 임시 다형성(오버로딩)은 컴파일 시점에, 포함 다형성(서브타이핑)은 런타임에, 매개변수 다형성(템플릿)은 컴파일 시점에 각 타입별 코드를 생성하고, 강제 다형성(캐스팅)은 타입 변환을 통해 구현됩니다. 상황에 맞는 다형성 기법을 적절히 활용하면 더 깔끔하고 확장 가능한 C++ 프로그램을 작성할 수 있습니다.