본 게시글은 면접준비 및 자기계발을 목적으로 작성된 게시글입니다
공부한 내용을 토대로 남들에게 설명할 수 있도록 이해하는 과정에 작성한 게시글이니 참고바랍니다
객체지향에서 다형성은 여러 가지 형태를 가질 수 있는 능력을 의미
상속을 통해 기능을 확장하거나 변경하는 것을 가능하게 해주고, 같은 클래스 내에서 코드의 길이를 줄여주는 것까지 도와주는 고마운 개념이다
다형성에는 크게 정적 다형성(Static Polymorphism), 동적 다형성(Dynamic Polymorphism)이 있다
정적 다형성은 컴파일 타임에 다형성이 결정되는 방식이다
C++에서는 함수 오버로딩(Overloading)과 템플릿(Template)을 통해 정적 다형성을 구현할 수 있다
👉 오버로딩 예시
#include <iostream> void print(int num) { std::cout << "정수: " << num << std::endl; } void print(double num) { std::cout << "실수: " << num << std::endl; } int main() { print(42); print(3.14); return 0; }
👉 템플릿 예시
#include <iostream> template <typename T> T add(T a, T b) { return a + b; } int main() { int a = 10; int b = 20; double c = 3.14; double d = 1.41; std::cout << add(a, b) << std::endl; std::cout << add(c, d) << std::endl; return 0; }
👉 추가 설명
템플릿을 사용하면 여러 타입에 대응되는 단 하나의 객체나 함수를 만들 수 있습니다.
템플릿은 C++ 프로그래밍 언어의 한 기능으로, 함수와 클래스가 제네릭 형과 동작할 수 있게 도와준다. 함수나 클래스가 개별적으로 다시 작성하지 않고도 각기 다른 수많은 자료형에서 동작할 수 있게 한다
템플릿의 타입은 컴파일 타임에 결정되어 인스턴스화 하기 때문에 컴파일타임에
컴파일러가 실제 코드 구현부를 모두 볼 수 있어야 합니다📌 인스턴스화는 컴파일러가 컴파일 시에 요구되는 타입으로 클래스 정의 코드를 생성해내는 것입니다. 즉 타입을 지정하여 그 타입을 사용하는 클래스를 만들어냅니다.
(ex. 만약 float타입으로 템플릿 클래스를 사용했다면 컴파일 타임에 컴파일러가 float 타입의 클래스를 만들어낸다, 이를 인스턴스화라고 함)
- 템플릿 클래스의 함수 구현은 헤더 파일에 들어가야 합니다
- 혹은 헤더 파일에서, 템플릿 정의부분 아래에 cpp파일을 인클루드 하는 방법도 있습니다. 이 방법을 사용할 때 주의할 점은 cpp파일을 빌드 리스트에 넣지 말아야 한다는 것입니다
동적 다형성은 런타임에 다형성이 결정되는 방식이다. C++에서는 상속(Inheritance)과 가상함수(Virtual Function)을 통해 동적 다형성을 구현할 수 있다
👉 동적 다형성(상속, 가상 함수) 예시
#include <iostream> class Animal { public: virtual void speak() { std::cout << "동물의 소리" << std::endl; } }; class Dog : public Animal { public: void speak() override { std::cout << "멍멍!" << std::endl; } }; class Cat : public Animal { public: void speak() override { std::cout << "야옹!" << std::endl; } }; int main() { Animal* animal1 = new Dog(); Animal* animal2 = new Cat(); animal1->speak(); animal2->speak(); delete animal1; delete animal2; return 0; }
ㅤㅤㅤㅤ구분ㅤㅤㅤㅤ | ㅤㅤㅤㅤOverridingㅤㅤㅤ | ㅤㅤㅤㅤOverloadingㅤㅤㅤ |
---|---|---|
적용 범위 | 상속 관계 | 같은 클래스 내 |
메서드 이름 | 부모 클래스와 자식 클래스 동일 | 부모 클래스와 자식 클래스 동일 |
매개 변수 | 부모 클래스와 자식 클래스 동일 | 부모 클래스와 자식 클래스 다름 |
리턴 타입 | 부모 클래스와 자식 클래스 동일 | 부모 클래스와 자식 클래스 다름 |
접근 제어자 | 자식 클래스가 부모 클래스보다 넓은 범위 가능 | 모든 접근제어자 가능 |
다형성을 사용하는 것은 코드의 재사용성과 유연성을 높여주지만, 코드의 복잡성과 디버깅 어려움, 성능 손실 등의 단점이 발생할 수 있으므로, 다형성을 적절하게 사용하는 것이 중요함
적절한 다형성을 사용하면 코드의 재사용성과 유연성을 높이고, 불필요한 코드 중복과 결합도를 낮춰 유지보수성을 높일 수 있습니다
1. 코드 재사용성(Reuse): 코드의 재사용성이 높아짐
개발자는 코드의 줍옥을 줄이고 생산성을 향상시킬 수 있음
2. 유연성(Flexibility): 객체의 형식을 추상화하고, 이를 사용하는 다른 객체에서 동일한 인터페이스를 사용할 수 있음
이를 통해 객체 간의 결합도를 낮추고, 코드의 유연성과 확장성을 높일 수 있음
3. 코드 가독성(Readability): 동일한 이름을 가진 메서드나 연산자가 서로 다른 동작을 하기 때문에, 코드의 가독성이 높아짐
이를 통해 개발자는 코드를 더 쉽게 이해하고, 유지보수를 수행할 수 있음
1. 복잡성(Complexity): 코드의 복잡성이 증가할 수 있음
다른 클래스에서 동일한 이름의 메서드나 연산자를 사용하기 때문에, 코드의 동작을 이해하는데 어려움이 있을 수 있음
2. 오버헤드(Overhead): 런타임 시에 메서드나 연산자의 동작을 결정하기 위해 추가적인 연산이 필요할 수 있음
이를 통해 일부 성능 손실이 발생할 수 있음
3. 디버깅(Difficulty Of Debugging): 코드의 실행 경로가 다양해져 디버깅이 어려울 수 있음. 이를 위해 디버깅을 위한 툴과 기법을 익혀야 하며, 이는 추가적인 학습 비용이 발생할 수 있음
다형성에 대해 (동적 다형성/정적 다형성)으로 구분하기도 하고 (메서드 오버로드/메서드 오버라이딩)으로 구분하기도 하는거 같은데 동적 다형성(=메서드 오버로드), 정적 다형성(=메서드 오버라이딩)으로 대응되는게 맞는걸까? 말하고자 하는 내용은 비슷한거같다
객체지향은 양날의 검이라고 생각이 들었다
객체지향은 확장성과 유지보수 측면에서 정말 좋은 방법이지만 그에비해 성능에 이슈가 발생하는거 같다
최근에 언리얼 공부를 하면서 배운 내용이다
이러한 특징을 가지고 있는데 언리얼은 일반 C++언어가 아닌 언리얼C++언어를 운용하여 성능과 안정성을 모두 지원한다는 점에서 매력적인 언어고 엔진이라고 생각이 들었다
📚 참고출처
얌얌코딩 (게임 개발) : https://youtu.be/D-STWJ24Kcs?si=SchohSwV6LRH3nZv
enamu.log : https://velog.io/@enamu/C에서의-다형성Polymorphism
hwisaac.log : https://velog.io/@hwisaac/OOP-다형성
이득우의 언리얼 프로그래밍 Part1 - 언리얼 C++의 이해