프로그래밍 언어/C & C++ 정리

다형성(Polymorphism)

뽀또치즈맛 2024. 11. 20. 17:07

 
poly 라는 것이 여러 개라는 뜻을 가지고 있다.
그럼 morphi는 뭘 뜻할까? 모습이란 뜻을 가지고 있다.
 
여러 모습 즉 다형성이다.
 
개체지향 프로그래밍에서 많이 쓰이는 것이 다형성이다.
 
다형성을 배우기 전에,
멤버 함수에 대해 알아보자.
 

멤버 함수에 대해 말해 보자.

다음 그림은 코드를 예시로
어떻게 스택과 힙에 메모리가 적재되는지 추상적으로 가시화한 것이다.

 

멤버 함수의 메모리

 

  • 멤버 함수도 메모리 어딘가에 위치해 있다.
    (사실 사용되는 모든 정보는 메모리에 어딘가에는 위치해 있어야 한다.)
    • 모든 것이 메모리 어딘가에 위치해 있어야 한다. 
      (함수 == 코드 섹션의 주소)
    • 근데 각 개체마다 멤버 함수의 메모리가 잡혀 있을까?
      • 아니다. 모든 개체는 함수 하나를 공유한다.
    • 그 대신 각 멤버 함수는 컴파일  시에 딱 한 번만 메모리에 "할당"된다.
      (할당 == 메모리 공간 확보)
      • 저수준에서 멤버 함수는 전역 함수와 그다지 다르지 않다.
// 저수준 언어로 표현한 main.cpp

myCat->GetName();
mov		ecx, dword ptr[myCat]	// myCat 주소를 저장
call 	Cat::GetName(0A16C7h)

yourCat->GetName();
mov		ecx, dword ptr[youtCat]	// yourCat 주소를 저장
call	Cat::GetName(0A16C7h)

 
결국 같은 주소지를 가리키므로,
멤버 함수도 저수준 수준에서는 전역 함수와 다를 것 없이 작동한다.
 
 

함수 오버라이딩

함수의 정의는 다르지만,
실제 함수의 작동 내용은 다른 것이 오버라이딩이다.

동적 바인딩인 오버라이딩과 정적 바인딩 오버로딩

 

 오버로딩

오버로딩은 자료형이 가진 해당 함수를 가져온다.
Java는 모든 함수는 기본적으로 자동 오버라이딩이 되지만,
Java는 프로그래머가 final 키워드를 쓰면
가상함수 말고 오버로딩으로 쓸 수 있다.
C++은 사용자 재량에 따라 기본적으로
멤버함수는 virtual 키워드를 적용하지 않았다면
오버로딩으로 접근하는 경우이다.
오버로딩은 컴파일 타임 바인딩으로
접근시 더 빠른 속도를 기대할 수 있다.
포인터의 자료형 그대로의 함수에 접근한다.

 오버라이딩


C++에서 오버라이딩은 오롯이 virtual만 쓸 수 있다. 

오버라이딩은
느린바인딩 혹은 런타임 바인딩이라고 한다.
포인터의 자료형 그대로 접근하지 않고
실 사용주인 포인터가 가르키고 있는 주소지의 자료형에 맞는
함수가 바인딩되어 접근한다.
이는 실행 중에 어떤 함수를 호출할지 결정하기 때문에
당연히 정적 바인딩보다 속도가 느리다.
 

가상테이블

실행 중에 어떤 함수를 호출할지 결정한다고 말했다.
이를 위해 가상 테이블이 생성되고,
가상 테이블에는 모든 멤버함수의 주소를 포함한다.
 
모든 가상 멤버함수의 주소를 포함한다고 했다.
그렇다면 클래스 마다 하나일까? 개체마다 하나일까?
 
당연히 클래스 마다 하나이다.
함수는 딱 하나다.
각 개체마다 함수를 가지지 않는다.
그렇기 때문에 가상 테이블도 클래스 마다 하나이다.
 
개체를 생성할 때, 해당 클래스의 가상 테이블 주소가 함께 저장된다.
이 말은 즉 개체가 해당 클래스의
가상 테이블에 있는 주소를 가진 그 주소지를 가리킨다는 것이다.
 
가상 테이블은 C에 없던 기능이다.
누군가 만든 것이다.
 
그럼 왜 느릴까?
뭔가 타고타고 가고 찾아야하고, 저장해야 하고,
당연히 느리다.
 
이 과정은 다음과 같다
어디 보자... 가상테이블에 어디에 있고... 
이거는 근데 두 번쨰 함수고... 여기 +4바이트 해서... 여기 저장된 주소에 있을 거야!
따라서 뛰어 넘어서 찾는다고해서
가상함수 테이블은 점프 테이블 혹은 룩업 테이블이라고도 한다.
 

동적 바인딩

 
가상 테이블의 멤버 함수 순서는 각 테이블이 상속관계를 가진다면
함수의 순서는 같아야 한다.
 

 
그럼 여기서 다른 YourCat이라는 변수가 힙에 존재한다면 어떨까?

 
똑같다.
같은 멤버 함수 주소지를 가리킨다.
이렇게 추상화한 그림을 보니,
왜 가상함수가 느릴 수 밖에 없는지,
어떻게 가상함수가
포인터가 가리키는 변수의 자료형에 맞게 찾아가는지 알 수 있을 것이다.
 
 

++ 추가 정보 ++
OOP의 개념에서 오버라이딩과 오버로딩은 아주 기본적인 개념이다.
만약 누군가 이 개념을 물었을 때 둘을 헷갈린다면,
굉장히 기본기가 약하고,
언어에 대한 이해도가 약하고 OOP를 잘 모르는구나 한다.
 
그러니 언어를 이해할 때는 달달 외우기 보단
아, 이래서 이렇구나. 라고 느낄 정도로 당연하게 받아들일 수 있도록
왜 그런지 알고 가자.
 

 

'프로그래밍 언어 > C & C++ 정리' 카테고리의 다른 글

인터페이스  (0) 2024.11.22
가상 소멸자와 비 가상 소멸자  (0) 2024.11.21
템플릿의 장단점  (0) 2024.11.19
범용 데이터 구조  (0) 2024.11.12
OOP - 상속  (0) 2024.11.11