산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Industrial programming >> C 언어

C++ 다형성 완전 정복: 컴파일타임/런타임 다형성, 가상 함수, 오버라이딩

C++에서 다형성이란?

C++에서 다형성은 멤버 함수가 이를 호출/호출하는 객체에 따라 다르게 동작하게 만듭니다. 다형성은 '여러 형태를 가지다'라는 뜻의 그리스어에서 유래했습니다. 상속을 통해 관련된 클래스 계층이 있을 때 발생합니다.

예를 들어, makeSound() 함수가 있다고 가정해 봅시다. 고양이가 이 함수를 호출하면 야옹 소리를 냅니다. 소가 같은 함수를 호출하면 음메 소리를 냅니다.

C++ 다형성 완전 정복: 컴파일타임/런타임 다형성, 가상 함수, 오버라이딩

하나의 함수지만 다른 상황에서 다르게 동작합니다. 함수가 여러 형태를 가지므로 다형성을 달성했습니다.

이 C++ 튜토리얼에서 배울 내용:

다형성 타입들

C++은 두 가지 다형성 타입을 지원합니다:

C++ 다형성 완전 정복: 컴파일타임/런타임 다형성, 가상 함수, 오버라이딩

컴파일 타임 다형성

인자의 개수와 타입을 매칭하여 오버로드된 함수들을 호출합니다. 이 정보는 컴파일 타임에 존재합니다. 즉, C++ 컴파일러가 컴파일 타임에 올바른 함수를 선택합니다.

컴파일타임 다형성은 함수 오버로딩과 연산자 오버로딩을 통해 달성됩니다.

함수 오버로딩

함수 오버로딩은 비슷하지만 다른 인자들을 가진 여러 함수들이 있을 때 발생합니다. 인자들은 개수나 타입 면에서 다를 수 있습니다.

예제 1:

 #include <iostream>
using namespace std;
void test(int i) {
    cout << " The int is " << i << endl;
}
void test(double f) {
    cout << " The float is " << f << endl;
}
void test(char const *ch) {
    cout << " The char* is " << ch << endl;
}
int main() {
    test(5);
    test(5.5);
    test("five");
    return 0;
} 

출력:

C++ 다형성 완전 정복: 컴파일타임/런타임 다형성, 가상 함수, 오버라이딩

코드 스크린샷:

C++ 다형성 완전 정복: 컴파일타임/런타임 다형성, 가상 함수, 오버라이딩

코드 설명:

  1. 코드에 iostream 헤더 파일 포함. 함수들 사용 가능해짐
  2. 코드에 std 네임스페이스 포함. 클래스 호출 없이 사용 가능
  3. 정수 매개변수 i를 받는 test 함수 생성. { 는 함수 test 본문 시작 표시
  4. 위 test 함수가 호출되면 실행될 문장
  5. 위 test 함수 본문 끝
  6. float 매개변수 f를 받는 test 함수 생성. { 는 함수 test 본문 시작 표시
  7. 위 test 함수가 호출되면 실행될 문장
  8. 위 test 함수 본문 끝
  9. 문자 매개변수 ch를 받는 test 함수 생성. { 는 함수 test 본문 시작 표시
  10. 위 test 함수가 호출되면 실행될 문장
  11. 위 test 함수 본문 끝
  12. main() 함수 호출. { 는 함수 본문 시작 표시
  13. 함수 test 호출하며 5를 인자 값으로 전달. 첫 번째 test 함수(정수 인자 받는 것) 호출됨
  14. 함수 test 호출하며 5.5를 인자 값으로 전달. 두 번째 test 함수(float 인자 받는 것) 호출됨
  15. 함수 test 호출하며 five를 인자 값으로 전달. 세 번째 test 함수(문자 인자 받는 것) 호출됨
  16. 프로그램 성공 실행 시 값 반환
  17. main() 함수 본문 끝

같은 이름을 가진 세 함수가 있지만 인자 타입이 다릅니다. 다형성을 달성했습니다.

연산자 오버로딩

연산자 오버로딩에서 우리는 C++ 연산자에 새 의미를 정의합니다. 연산자 작동 방식도 변경됩니다. 예를 들어 + 연산자를 두 문자열 연결로 정의할 수 있습니다. 우리는 이를 숫자 값 더하기용 덧셈 연산자로 알고 있습니다. 우리 정의 후, 정수 사이에 놓이면 더하고, 문자열 사이에 놓이면 연결합니다.

예제 2:

 #include<iostream>
using namespace std;
class ComplexNum {
private:
    int real, over;
public:
    ComplexNum(int rl = 0, int ov = 0) {
        real = rl;
        over = ov;
    }
    ComplexNum operator + (ComplexNum const &obj) {
        ComplexNum result;
        result.real = real + obj.real;
        result.over = over + obj.over;
        return result;
    }
    void print() {
        cout << real << " + i" << over << endl;
    }
};
int main() {
    ComplexNum c1(10, 2), c2(3, 7);
    ComplexNum c3 = c1+c2;
    c3.print();
} 

출력:

C++ 다형성 완전 정복: 컴파일타임/런타임 다형성, 가상 함수, 오버라이딩

코드 스크린샷:

C++ 다형성 완전 정복: 컴파일타임/런타임 다형성, 가상 함수, 오버라이딩

C++ 다형성 완전 정복: 컴파일타임/런타임 다형성, 가상 함수, 오버라이딩

코드 설명:

  1. 프로그램에 iostream 헤더 포함하여 함수 사용
  2. 프로그램에 std 네임스페이스 포함하여 클래스 호출 없이 사용
  3. ComplexNum이라는 클래스 생성. { 는 클래스 본문 시작 표시
  4. private 접근 지정자로 변수들을 private 표시. 클래스 내부에서만 접근 가능
  5. 정수 변수 real, over 정의
  6. public 접근 지정자로 생성자 public 표시. 클래스 외부에서도 접근 가능
  7. 클래스 생성자 생성 및 변수 초기화
  8. 변수 real 값 초기화
  9. 변수 over 값 초기화
  10. 생성자 본문 끝
  11. + 연산자 의미 오버라이드 필요
  12. ComplexNum 타입의 result 데이터 타입 생성
  13. 복소수에 + 연산자 사용. 이 줄은 한 숫자의 실부를 다른 숫자의 실부에 더함
  14. 복소수에 + 연산자 사용. 이 줄은 한 숫자의 허부를 다른 숫자의 허부에 더함
  15. 프로그램 성공 실행 시 result 변수 값 반환
  16. + 연산자 새 의미 정의 끝, 즉 오버로딩
  17. print() 메서드 호출
  18. 덧셈 후 새 복소수 콘솔 출력
  19. print() 함수 본문 끝
  20. ComplexNum 클래스 본문 끝
  21. main() 함수 호출
  22. 실부와 허부 값들을 전달하여 더함. c1 첫 부분이 c2 첫 부분에 더해짐(10+3). c1 두 번째 부분이 c2 두 번째 부분에 더해짐(2+7)
  23. 오버로드된 + 연산자 사용한 연산 수행하고 결과를 변수 c3에 저장
  24. 변수 c3 값 콘솔 출력
  25. main() 함수 본문 끝

런타임 다형성

이것은 객체의 메서드가 컴파일 타임이 아닌 런타임에 호출/실행될 때 발생합니다. 런타임 다형성은 함수 오버라이딩을 통해 달성됩니다. 호출될 함수는 런타임에 확정됩니다.

함수 오버라이딩

함수 오버라이딩은 기본 클래스의 함수가 파생 클래스에서 새 정의를 받을 때 발생합니다. 그때 기본 함수가 오버라이드되었다고 말합니다.

예를 들어:

 #include <iostream>
using namespace std;
class Mammal {
public:
    void eat() {
        cout << "Mammals eat...";
    }
};
class Cow: public Mammal {
public:
    void eat() {
        cout << "Cows eat grass...";
    }
};
int main(void) {
    Cow c = Cow();
    c.eat();
    return 0;
} 

출력:

C++ 다형성 완전 정복: 컴파일타임/런타임 다형성, 가상 함수, 오버라이딩

코드 스크린샷:

C++ 다형성 완전 정복: 컴파일타임/런타임 다형성, 가상 함수, 오버라이딩

코드 설명:

  1. 프로그램에 iostream 헤더 파일 가져와 함수 사용
  2. 프로그램에 std 네임스페이스 포함하여 클래스 호출 없이 사용
  3. Mammal이라는 클래스 생성. { 는 클래스 본문 시작 표시
  4. public 접근 지정자로 곧 만들 함수를 공개 접근 가능하게 설정. 이 클래스 외부에서도 접근 가능
  5. eat이라는 public 함수 생성. { 는 함수 본문 시작 표시
  6. eat() 함수 호출 시 cout 함수에 추가될 문장 출력
  7. eat() 함수 본문 끝
  8. Mammal 클래스 본문 끝
  9. Mammal 클래스를 상속하는 Cow 클래스 생성. Cow는 파생 클래스, Mammal은 기본 클래스. { 는 이 클래스 시작 표시
  10. public 접근 지정자로 곧 만들 함수를 공개 접근 가능하게 설정. 이 클래스 외부에서도 접근 가능
  11. 기본 클래스에 정의된 eat() 함수 오버라이드. { 는 함수 본문 시작 표시
  12. 이 함수 호출 시 콘솔에 출력할 문장
  13. eat() 함수 본문 끝
  14. Cow 클래스 본문 끝
  15. main() 함수 호출. { 는 이 함수 본문 시작 표시
  16. Cow 클래스 인스턴스 생성하고 이름 c 부여
  17. Cow 클래스에 정의된 eat() 함수 호출
  18. 프로그램 성공 완료 시 값 반환
  19. main() 함수 끝

C++ 가상 함수

가상 함수는 C++에서 런타임 다형성을 구현하는 또 다른 방법입니다. 기본 클래스에서 정의되고 파생 클래스에서 재정의되는 특수 함수입니다. 가상 함수를 선언하려면 virtual 키워드를 사용해야 합니다. 키워드는 기본 클래스에서 함수 선언 앞에 와야 합니다.

가상 함수 클래스가 상속되면, 파생 클래스는 자신의 필요에 맞게 가상 함수를 재정의합니다. 예:

 #include <iostream>
using namespace std;
class ClassA {
public:
    virtual void show() {
        cout << "The show() function in base class invoked..." << endl;
    }
};
class ClassB :public ClassA {
public:
    void show() {
        cout << "The show() function in derived class invoked...";
    }
};
int main() {
    ClassA* a;
    ClassB b;
    a = &b;
    a->show();
} 

출력:

C++ 다형성 완전 정복: 컴파일타임/런타임 다형성, 가상 함수, 오버라이딩

코드 스크린샷:

C++ 다형성 완전 정복: 컴파일타임/런타임 다형성, 가상 함수, 오버라이딩

코드 설명:

  1. 코드에 iostream 헤더 파일 포함하여 함수 사용
  2. 코드에 std 네임스페이스 포함하여 클래스 호출 없이 사용
  3. ClassA라는 클래스 생성
  4. public 접근 지정자로 클래스 멤버를 공개 접근 가능하게 표시
  5. show()라는 가상 함수 생성. public 함수
  6. show() 호출 시 출력할 텍스트. endl은 줄바꿈을 의미하는 C++ 키워드
  7. 가상 함수 show() 본문 끝
  8. ClassA 클래스 본문 끝
  9. ClassA 클래스를 상속하는 ClassB라는 새 클래스 생성. ClassA는 기본 클래스, ClassB는 파생 클래스
  10. public 접근 지정자로 클래스 멤버를 공개 접근 가능하게 표시
  11. 기본 클래스에서 정의된 가상 함수 show() 재정의
  12. 파생 클래스에서 정의된 show() 함수 호출 시 콘솔에 출력할 텍스트
  13. show() 함수 본문 끝
  14. 파생 클래스 ClassB 본문 끝
  15. main() 함수 호출. 프로그램 로직은 본문 내에 추가
  16. ClassA 클래스를 가리키는 포인터 변수 a 생성
  17. ClassB 클래스 인스턴스 생성하고 이름 b 부여
  18. b에 저장된 주소 값을 변수 a에 할당
  19. 파생 클래스에 정의된 show() 함수 호출. 지연 바인딩 구현됨
  20. main() 함수 본문 끝

컴파일타임 다형성 vs 런타임 다형성

주요 차이점들:

컴파일타임 다형성런타임 다형성
초기 바인딩 또는 정적 다형성이라고도 함지연/동적 바인딩 또는 동적 다형성이라고도 함
메서드는 컴파일 타임에 호출/실행됨메서드는 런타임에 호출/실행됨
함수 오버로딩과 연산자 오버로딩으로 구현메서드 오버라이딩과 가상 함수로 구현
예: 메서드 오버로딩. 여러 메서드가 비슷한 이름지만 인자 개수나 타입이 다름예: 메서드 오버라이딩. 여러 메서드가 비슷한 이름과 같은 프로토타입을 가짐
메서드 발견이 컴파일 타임에 이루어지므로 더 빠른 실행메서드 발견이 런타임에 이루어지므로 더 느린 실행
컴파일 타임에 모든 것이 알려지므로 문제 해결 유연성 적음메서드가 런타임에 발견되므로 복잡한 문제 해결에 더 많은 유연성 제공

요약:

C 언어

  1. C++ 배열을 함수에 전달하는 방법: 실전 가이드
  2. C++ 연산자 총정리: 종류, 예제, 샘플 프로그램
  3. C++ switch-case 마스터하기: 문법, 활용법, 실전 예제
  4. C++ 동적 배열 할당 완벽 가이드: new, delete, 실전 코드 예제
  5. C++ 연산자 오버로딩 실전 가이드: 문법, 접근법, 코드 예제
  6. C++ 구조체(struct) 완벽 가이드: 선언, 인스턴스, 포인터, 함수 인자 전달
  7. C++ std::list 마스터하기: 문법, 함수, 실전 예제
  8. C++ 함수 완전 정복: 실전 코드 예제로 이해하기
  9. C++ 구조체 vs 클래스: 핵심 차이, 문법, 최적 사용 사례
  10. C언어 calloc(): 제로 초기화 메모리 할당과 실전 예제