C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 Q&A
C++Builder Programming Q&A
[26162] Re:[질문] virtual 이라고 선언한것
임문환.실업자 [origin] 893 읽음    2003-06-30 18:22
김무성 님이 쓰신 글 :
: class TColorForm : public TForm
: {
: __published:
: private:   
: public:   
:         virtual __fastcall TColorForm(TComponent* Owner);
:         virtual __fastcall TColorForm(String *str,TComponent* Owner);
: };
:
:
: 버추얼 선언을 해도,하지 않아도 마찬가지로 컴파일이 둘다 되고
: 실행상의 별 다른점이 없는것 같은데 뭐가 다른가요?

현재 님이 제시한 코드에서는 생성자에든 소멸자에든 virtual이 있으나 없으나 다를 게 없습니다.
그 이유는 아래와 같습니다.

- 생성자는 virtual 이 될 수 없습니다.
(님의 예인 VCL 클래스에서는 virtual 키워드를 붙여도 컴파일 되는 게 이상하군요. 아마도 컴파일러가 virtual 키워드를 그냥 무시하거나 고유의 용도와는 다른 용도로 사용하는 것 같은데... 왜 오류가 안 나는지 아시는 분 설명 부탁드립니다.)
가상함수 논리는 포인터나 참조의 형을 기준으로 하지 않고 그게 가리키는 실제 인스턴스의 형을 기준으로 함수를 호출하는 것입니다.
생성자가 virtual이 되게 하려는 의도는 new Base1;을 했을 때 Derived가 생성되도록 하는 것일 겁니다.
상속선상에 있는 각 클래스의 초기화 순서는 최상위 조상클래스에서 시작해 현재 클래스까지입니다.
생성자가 호출되려면 반드시 해당 클래스 이름을 지정해야 할뿐만 아니라 아직 인스턴스가 생성되지도 않은 상태여서 가상함수 호출에 필요한 정보들이 생성되지 않은 상태입니다.
또한, Base1 클래스 입장에서는 파생 클래스가 반드시 있어야 된다는 법도 없는 것이고 막상 파생 클래스가 만들어진다 하더라도 파생 클래스의 구조가 Base1 이전에 미리 정해진 것도 아니고 파생 클래스가 한 가지뿐이라는 보장이 없어서 어떤 파생 클래스의 인스턴스를 생성해야 할지 알 수 없게 됩니다. 후손은 조상에 대해 알 수 있지만 조상은 태어나지도 않은 모든 후손에 대해 알 수는 없는 것입니다. 엄청난 예지력을 지닌 이는 가능할 지도 모르지요^^
따라서, 생성자에는 가상함수 논리를 적용할 수 없는 것입니다.

- 소멸자에는 virtual 키워드를 붙이면 효과가 발생합니다.
다만, 님이 제시한 코드의 경우 TForm의 소멸자가 virtual이므로 TColorForm의 소멸자에 virtual이 있든 없든 자동으로 virtual이 됩니다. __fastcall virtual ~TForm(void) { }

소멸자에 virtual 키워드를 붙여주면 발생하는 효과:
#include<iostream>
using namespace std;
class TheOrigin
{
public:
  ~TheOrigin(){cout<<"~TheOrigin()\n";}
};

class Base1:public TheOrigin
{
public:
virtual ~Base1(){cout<<"~Base1()\n";}
};

class Derived:public Base1
{
public:
~Derived(){cout<<"~Derived()\n";}
};

int main(void)
{
Base1* bp = new Derived;
delete bp;
}

출력:
~Derived()
~Base1()
~TheOrigin()

소멸자가 호출되는 순서: 해당 클래스에서 시작해서 기초클래스 방향으로 진행.

만약 Base1의 소멸자가 virtual이 아니라면 ~Base1()이 호출되어 자신을 비롯해서 조상 클래스 방향의 모든 소멸자가 호출됩니다. ~Derived()는 호출되지 않습니다. 소멸자가 하는 일이 메모리에서 자신을 제거하는 일이므로 그게 호출되지 않는다는 것은 메모리 누수(leak) 발생을 의미합니다.

반면, Base1의 소멸자가 virtual이라면 가상함수의 원리에 따라 ~Derived()가 호출됩니다. Derived에서 시작해서 조상 클래스 방향의 모든 소멸자가 호출됩니다. 즉, 현재 예와 같이 모두 메모리에서 제거됩니다.

위와 같이 볼 때, 소멸자에 virtual 키워드를 붙일지 여부는 자신으로 부터 파생될 클래스가 있을 지 여부와 밀접한 관련이 있습니다. 자신으로부터 파생될 클래스가 있을 수 있다면 virtual 키워드를 붙여주는 것이 좋지만 전혀 그렇지 않다면 굳이 붙일 이유가 없습니다.
(물론, 해당 클래스의 소멸자가 virtual이라면 그 하위 클래스들의 소멸자는 virtual 키워드 여부와는 상관 없이 자동으로 virtual입니다.)

: 예전 BC31에서는 버추얼 선언하지 않으면
: 아예 컴파일 안되었던것 같은데
: 제가 착각하는건가요?
:

BC31은 안 써봐서 모르겠습니다.

+ -

관련 글 리스트
26143 [질문] virtual 이라고 선언한것 김무성 717 2003/06/30
26162     Re:[질문] virtual 이라고 선언한것 임문환.실업자 893 2003/06/30
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.