객체가 완전히 생성되기 이전에 가상 함수를 호출하면 이상 동작을 일으킨다. 어떤 타입이든

생성자가 수행을 완료할 때까지는 객체가 완전히 생성되었다고 할 수 없다. 따라서 생성자 내에서

가상 함수를 호출하면 예상처럼 동작하지 않는다. 다음 코드를 살펴보자.

Class B
{
		protected B()
		{
				VFunc();
		}

		protected virtual void VFun()
		{
				Console.WriteLine("VFunc in B");
		}
}

Class Derived : B
{
		private readonly string msg = "Set by initializer";

		public Derived(string msg)
		{
				this.msg = msg;
		}

		protected override void VFunc()
		{
				Console.WritLine(msg);
		}

		public static void Main()
		{
				var d = new Derived("Constructed in main");
		}

앞의 코드를 수행하면 ‘Constructed in main’, ‘VFunc in B’, ‘Set by initializer’ 중 무엇이 출력될 것

같은가? 숙련된 C++ 개발자라면 ‘VFunc in B’라고 답을 할지도 모르겠다. 일부 C# 개발자들은

‘Constructed in main’이라고도 할 것 같다. 하지만 답은 ‘Set by initializer’다.

베이스 클래스의 생성자를 살펴보면 자기 클래스 내에 정의된 가상 함수를 호출하고 있다. 하지만

파생 클래스가 가상 함수를 이미 재정의하고 있기 때문에 런타임에는 파생 클래스에서 재정의한

함수가 호출된다. 왜냐하면 런타임에 객체의 타입이 Derived이기 때문이다. C#의 정의에 따르면

생성자의 본문으로 진입하는 순간 해당 객체는 이미 초기화가 완료된 것으로 간주한다.

모든 멤버 변수를 초기화 구문을 이용하여 초기화할 수 있을런지는 모르겠지만, 대부분의 경우 모든

멤버 변수가 이 시점에 유효한 값을 갖도록 초기화되었다고 단정하기는 어렵다. 단지 멤버 변수에

대한 초기화 구문을 완료했을 뿐이며 실상 파생 클래스의 생성자 본문은 아직 수행조차 되지 않았기

때문이다.

이 때문에 객체를 생성하는 동안 가상 함수를 호출하면 일관성 문제가 발생할 수 있다. C++의 경우

가상 함수가 생성 중인 객체의 타입을 확인하도록 설계되었다. 또한 런타임에 객체의 타입은 객체가