정리필요2

virtual 키워드

ShineWithMe 2008. 6. 27. 20:53

[네이버 지식인에서 퍼옴]


virtual 이라는 키워드가 붙게되면...이 virtual 붙은 것은 실시간,,,즉,,,컴파일이 된 후의

 

런타임에 바인딩되어 호출될 함수가 결정되죠~~

 

정적, 동적 바인딩이 여기서 등장하죠...

 

가상함수는 객체 타입의 포인터를 이용하여 호출할 때 의미가 있는 것이지,

 

포인터 타입이 아닌 인스턴스로는 호출이 되지 않습니다...(중요 !!)

 

보통,,,부모 클래스에서 가상함수를 선언했을 경우, 자식 클래스에서 이 함수를

 

virtual 키워드 없이 오버라이딩 해도 되지만,,,이 함수는 가상함수이다~~ 이렇게

 

명확히 알려주도록 하기위해, 자식 클래스에도 virtual 키워드를 붙여 주는것이

 

좋습니다...

 

class A{....

virtual void fct(){cout<<"1";}

};

class B : public A{....

virtual void fct(){cout<<"2";}  // 명확히 virtual 을 붙여주는 것이 좋다 !!

};

 

뭐 이렇게 하고 메인에서 A *a = new A; a->fct; 이렇게 하면 '2' 가 출력되는...

(맞죠??? 갑자기 헷갈리네. A a 라고 선언하고  a.fct 해도 똑같이 2가 나올려나요???

해봐야지)

 

==> A 타입의 포인터 a 는 A 타입의 객체를 생성하였으므로,,,A 타입 클래스의

 

       멤버만을 알고 있습니다...그러니,,,'2' 가 출력되는 것이 아니고 '1' 이

 

      출력되죠 !!

 

 

 

class A{}

class B : virtual  public A{}

class C : virtual public A{}

class D : public B, public C{}

 

 

=> 여기서 virtual 의 의미는??

 

     virtual 이 붙은 가상 기반 클래스는 잘 알다시피, "모호성" 을 피하기

 

    위함입니다...

   

     가상 기반 클래스가 아니라면...D 클래스가 생성시에 A 를 상속 받을 때,

 

     B에서 받을지 ??  C에서 받을지 모호하죠~~...컴파일러는 애매모호한 것을 아주

 

    싫어 합니다...

 

    그러므로,,,virtual 키워드로 인해, D 클래스에서는 B 와 C 클래스가 상속받은

 

    A 클래스를 하나로 인지하도록 하여, 모호성을 없애주고, D 는 오직 하나의

 

    A 클래스만을 인식합니다...

 

 

*** 알아 두어야 할 점 ***

 

보통, 상속의 경우에는 자식은 부모의 생성자 만을 호출할 수 있으나,

 

가상 기반 클래스에서는 손자가 할아버지의 생성자를 호출한다는 점입니다...

 

즉,  손자 -> 할아버지 생성자를 바로 호출할 수 있다는 것이죠...

 

또한, 중간 단계의 클래스인 아버지 생성자(위에서는 B, C 레벨) 에서는

 

A 의 생성자를 호출하지 않습니다..  A 는 B, C 의 것이 아닌 D 의 것이기

 

때문입니다...

 

예를 들어 봅니다..

 

 

class A{
protected :
 int a;
public :
   A(int _a) : a(_a) { cout<<"A 생성"<<endl; }
 ~A( ) { cout<<"A 소멸"<<endl; }

};

 

class B : virtual public A{
protected :
 int b;
public :

    // A의 생성자 호출이 안됨

   B(int _a, int _b) : A(_a), b(_b) { cout<<"B 생성"<<endl; }
 ~B( ) { cout<<"B 소멸"<<endl; }

};

 

class C : virtual public A{
protected :
 int c;
public :

   // A의 생성자 호출이 안됨

   C(int _a, int _c) : A(_a), c(_c) { cout<<"C 생성"<<endl; }
 ~C( ) { cout<<"C 소멸"<<endl; }
    };

 

class D : public B, public C{
 int d;
public :

  // A의 생성자를 D에서 호출 !!...A 클래스의 멤버변수의 값은 B, C 클래스에서

  // 넘겨준 값은 무시되고, 직접 호출한 A 의 생성자 값만 인식한다 !!
 D(int _a, int _b, int _c, int _d) : A(_a + 100), B(_a + 1, _b), C(_a + 1, _c), d(_d) { }


 void Print( )
 {
  cout<<"a: "<<a<<endl;
  cout<<"b: "<<b<<endl;
  cout<<"c: "<<c<<endl;
  cout<<"d: "<<d<<endl;
 }
};

 

int main()
{
 D ob(1, 2, 3 ,4);   // 인스턴스 생성 !!

 

 ob.Print();
}

 

위에서 보다시피,,,B 와 C 가 생성될 때는 별도로, A 의 생성자를 호출하지

 

않음을 알 수 있습니다...

 

D 에서 호출한 A의 생성자만 호출 됨을 알수 있죠~~

 

원래는 부모의 생성자를 호출해야 하지만...

 

A 생성

 

A 생성

B 생성

 

A생성

C 생성

.....

 

이런식으로 되어야 하는데 말이죠...이는 A 를 소유한 것은 B 와 C가 아닌

 

D 클래스 라는 것을 의미합니다...좀 특이한 형태죠...