본문 바로가기

PL/C & C++

[C++] virtual

가상 함수는 기본 클래스(상속되지 않은 클래스) 내에서 선언되어 파생 클래스에 의해 재정의되는 맴버 함수입니다.

포인터(Pointer) 또는 기본 클래스에 대한 참조(Reference)를 사용하여 파생 클래스의 객체를 참조하면 해당 객체에 대해

가상 함수를 호출하고 파생 클래스의 함수를 실행할 수 있습니다.

이는 주로 실행시간(Runtime)에 함수의 다형성(Polymorphism)을 구현하는데 사용됩니다.

가상 함수는 기본 클래스내에 virtual 키워드로 함수를 선언합니다.

 

parent 클래스를 가리키는 포인터 p를 선언하고, child 클래스의 객체 c를 선언했습니다.

이 포인터 p는 c객체를 가리킵니다.

몸체는 parent 클래스지만 실제 객체는 child 클래스입니다.

이 포인터 p를 이용하여 가상 함수인 v_print()와 오버라이딩 된 함수 print()를 출력하면 각각의 함수는

어느 클래스에서 호출될까요? 답은 아래와 같습니다.

 

v_print() 함수는 가상 키워드로 선언되어 가상 함수가 되었으며

가상 함수는 실행시간(런타임)에 그 값이 결정됩니다. (후기 바인딩이라고도 합니다.)

포인터 p에는 child 클래스의 객체가 들어가 있고 포인터가 가리키는 위치에 따라 child 클래스의 v_print() 함수가 호출되었으며

일반 함수인 print()는 컴파일 시간에 이미 결정되기 때문에 31번째 줄에 p에서 print() 함수를 호출할 때

parent 클래스의 print() 함수가 호출되는것으로 결정이 끝나버린 상태입니다.

따라서 parent 클래스의 print() 함수가 호출되게 됩니다.

 

위 예제 코드를 보시면 parent 클래스에서 print1() 함수는 일반 함수로 선언되었으며,

print2(), print3() 함수는 virtual 키워드를 통해 가상 함수로 선언되었습니다.

또한 상속받은 child 클래스에서 print3() 함수는 오버라이딩하여 매개변수를 추가했습니다.

똑같이 parent 클래스의 포인터를 선언하여 파생 클래스인 child 클래스의 객체를 참조하고 포인터를 통해

print1(), print2(), print3() 함수를 호출하면 어떤 결과가 도출될까요?

 

실행 결과

 


print1() 함수는 일반 함수이기 때문에 컴파일 시간에 결정이 나고 parent 클래스의 print1() 함수가 호출됩니다.

print2() 함수는 가상 함수이기 때문에 실행 시간에 결정이 됩니다. parent 클래스지만 가리키고있는 객체가 child 클래스이기 때문에

child 클래스의 print2() 함수가 호출되게 됩니다.

print3() 함수는 가상 함수이지만 child 클래스에서는 매개변수가 없는 함수를 호출했기 때문에 부모 클래스인 parent 클래스의

print3() 함수가 호출되게 된 것입니다.




 

C++ 가상 함수(Virtual Function)

안녕하세요 열코입니다. 이번 시간에는 C++ 클래스의 가상 함수(Virtual Function)에 대해 알아보도록 하겠습니다. 가상 함수는 기본 클래스(상속되지 않은 클래스) 내에서 선언되어 파생 클래스에

yeolco.tistory.com

 


 

 

 

 

a_2 포인터 변수에 주목해 봅시다.

a_2 포인터가 가르키는 함수에는 일반함수와 가상함수가 있으며 이를 B클래스에서 모두 오버라이딩 하고 있습니다.

하지만 결과는 같은 오버라이딩이여도 가상함수로 선언된 show_P() 함수만 B클래서의 함수를 호출하고 있습니다.

이는 가상함수에 대한 약속인데, 

가상함수로 선언된 맴버 함수가 있고 이를 오버라이딩한 자식 클래가 존재 한다면, 형변환이 이뤄진 포인터 변수는

자식 클래스의 오버라이딩된 함수를 호출할 수 있는 기능이 생깁니다.

 

 

 

그럼 이 경우 어느때 쓰느냐??

 

부모클래스 밑에 자식클래스가 여러개 있다고 가정했을 때, 모든 자식들을 형변환을 통해 부모 클래스로 묶어서 관리를 할 때 입니다.

모든 자식클래스들은 부모클래스로 형변환 되어 관리되고 있다가, 자식클래스에 있는 변수정보가 필요할 때 가상함수를 통해

접근할 수 있도록 한 것입니다.

 

(가상함수를 만들면 기본적으로 V-table이 생성되는데 컴파일러는 V-table에 있는 함수 주소값을 토대로 호출 대상을 찾게 됩니다.)

 

 

※ 주의할 점은 포인터로 선언된 변수의 경우만 가능합니다. 왜냐 하면 V-table에 있는 주소 값을 기반으로 찾아가기 때문입니다.

따라서 일반적인 객체로 선언할 경우, 

ex)

A a;   

B b;   

 

a = b;   

 

a.show_P();

 

가상함수의 기능을 상실해(V-table에 접근할 수 없기 때문에) class A의 show.P()메소드를 호출하게 됩니다.

 

 

 

 

C++ virtual 함수란?

※해당 글의 내용이 다소 부족하다 생각하여 다시 정리해서 글을 썻습니다. https://hwan-shell.tistory.com/225 부족하다 느끼시는 분들은 참고해 주세요!! virtual(가상함수)에 들어가기 앞서 두 개념을 짚

hwan-shell.tistory.com

 

'PL > C & C++' 카테고리의 다른 글

[C] 매개변수 배열의 크기  (0) 2021.03.23
[C & C++] 함수에서 배열 매개변수 사용하기  (0) 2021.03.23
[C++] auto  (0) 2021.03.09
[C++] 스마트 포인터, unique_ptr  (0) 2021.03.08
[C++] 깊은 복사 , 얕은 복사  (0) 2021.03.05