-
virtual 키워드정리필요2 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 클래스 라는 것을 의미합니다...좀 특이한 형태죠...