C#에서 참조 타입에 대한 생성자는 아래와 같은 특징을 가진다.
0, null로 초기화 된다.상속 관계에서 생성차 호출 순서는 어떻게 될까? 아래의 예제코드를 보자.
class Base
{
public Base() { Console.WriteLine("Base"); }
public Base(int n) { Console.WriteLine($"Base: {n}"); }
}
class Derived : Base
{
public Derived() { Console.WriteLine("Derived"); }
public Derived(int n) { Console.WriteLine($"Derived: {n}"); }
}
public static void Main(string[] args)
{
Derived d = new Derived();
}
메인 함수에서 Derived 객체를 생성하면 자동으로 Base 클래스의 생성자를 호출하게 되는데, 위의 코드의 실행결과는 "Base"가 먼저 출력되고 다음으로 "Derived"가 출력된다.

상속된 객체를 생성할 때, 생성자의 호출 순서의 특징은 다음과 같다.
기본적으로 컴파일러는 Derived의 생성자 부분을 아래 코드와 같이 변경하는데 base()에 해당하는 부분을 직접 적어주어도 되고 Base 클래스의 생성자를 직접 호출할 수도 있다.
class Derived : Base
{
public Derived() : base() { Console.WriteLine("Derived"); }
public Derived(int n) : base() { Console.WriteLine($"Derived: {n}"); }
}
Base의 생성자가 public이 아니라면 어떻게 될까? private이라면 외부에서 객체를 생성할 수 없을 것이니 protected라면 Derived 클래스에서 Base의 생성자를 호출할 수 있다.
class Animal
{
protected Animal() { }
}
class Dog : Animal
{
public Dog() { }
}
public static void Main(string[] args)
{
Animal a = new Animal(); // Error!
Dog d = new Dog(); // Ok!
}
위 코드를 보면 메인함수에서 Animal 객체를 직접 생성할 수는 없다. 하지만 Dog 객체는 생성이 가능하다. 즉, Base 클래스의 생성자를 protected로 해놓으면 Base 객체를 생성할 수는 없지만 Base를 상속받은 객체는 생성이 가능하다는 것이다.
Base 클래스에 가상함수가 존재하고 Derived 클래스에서 이를 재정의 한다면 어떤 클래스의 함수를 호출하게 되는지 헷갈릴 수 있다. 아래 예제코드를 봐보자.
class Base
{
public Base() { Foo(); }
public virtual void Foo() { Console.WriteLine("Base.Foo"); }
}
class Derived : Base
{
public int a = 100;
public int b;
public Derived() { b = 100; }
public override void Foo() { Console.WriteLine($"Derived.Foo: {a}, {b}"); }
}
위와 같은 코드가 있을 때, Derived 객체를 생성하게 된다면 어떻게 될까? 헷갈릴만한 부분이 여러군데가 있다.
실행해보기 전 내 생각에는 100, 100이 출력될 줄 알았는데 실행해보면 100, 0이 출력되는 것을 확인할 수 있다.

컴파일러는 컴파일 단계에서 Derived의 생성자를 다음과 같이 수정하게 되는데 아래 코드를 보면 Base 생성자를 호출하기 전에 초기화되어있는 필드를 초기화 한 뒤에 Base 생성자를 호출하는 것을 볼 수 있다.
public Derived() {
a = 100;
Base();
b = 100;
}