생성자(Constructor)
생성자
- 클래스의 객체가 만들어질 떄 자동으로 실행되는 메서드
- 필드(멤버 변수) 초기화, 객체를 사용할 준비를 함
- 클래스와 동일한 이름
- 반환형이 없음(void도 아니다)
- 객체가 생성될 때 단 한 번만 실행
- 매개변수를 받을 수도 있고, 아닐 수도 있다
- 생성자가 정의되지 않으면 컴파일러가 자동으로 기본 생성자를 제공한다.
- 오버로딩(Overloading, 과적)이 가능하다. (여러 개의 생성자를 만들 수 있다)
기본 생성자
비어있는 생성자를 두면 위와 같은 것이 뜬다.
Empty constructor is redundant. the compiler generates the same by default.
이는 클래스 내에서 아무런 생성자도 정의하지 않으면 자동으로 기본 생성자를 생성해 주기 때문에 굳이 왜 빈 생성자를 쓰냐고 말해주는 것이다.
두 번째
Non - nullable field 'name' is uninitialized. Consider adding the 'required' modifier or declaring the field as nullable.
name이 Non - nullable field로 선언되었다는 것이다.
C#에서 string 은 기본적으로 null 값을 가질 수 없기 때문에 다음과 같이 required를 사용하거나,
null이 될 수 있게 바꿔주어야 한다.
int형은 기본값인 0이 할당되기 때문에 오류가 뜨지 않는 것이다.
class test
{
public static void Main()
{
Person p = new Person();
Console.WriteLine(p.name);
Console.WriteLine(p.age);
}
}
class Person
{
public string name;
public int age;
}
class test
{
public static void Main()
{
Person p = new Person();
Console.WriteLine(p.name);
Console.WriteLine(p.age);
}
}
이렇게 실행해도 똑같은 결과가 나온다. 즉, 기본으로 생성자는 자동으로 생성된다.
다만, 기본 생성자가 자동으로 제공되더라도 명시적으로 정의하는 것이 더 안전할 수 있다.
매개변수를 갖는 생성자
생성자는 매개변수를 가질 수도 있다. 이를 통해 객체 생성 시 값을 전달하여 초기화할 수 있다.
using System;
class Person
{
public string name;
public int age;
public Person(string name, int age)
{
this.name = name;
this.age = age;
Console.WriteLine("매개변수가 있는 생성자 호출");
}
}
class test
{
public static void Main()
{
Person p = new Person("홍길동",300);
Console.WriteLine(p.name);
Console.WriteLine(p.age);
}
}
Base키워드를 사용한 부모 생성자 호출
우리는 보통 상속을 통해 부모 클래스의 속성과 기능을 자식 클래스에서 그대로 사용한다.
하지만 생성자는 상속되지 않기 때문에 자식 클래스에서 부모 클래서의 생성자를 직접 호출해야 하는 경우가 있다.
예를 들어, 부모 클래스의 필드를 초기화해야 할 경우가 있다.
부모 클래스에서 공통적으로 정의해둔 필드들, 그리고 생성자를 모든 자식 클래스에서 동일하게 사용하는 것은 낭비다.
따라서 자식 클래스에서 따로 정의되어야 할 부분들만 써 줄 수 있다.
using System;
class Employee
{
public string Name;
public int ID;
// 부모 클래스의 생성자: 직원의 이름과 ID를 초기화
public Employee(string name, int id)
{
Name = name;
ID = id;
Console.WriteLine($"[Employee 생성자] 직원 생성됨: {Name}, ID: {ID}");
}
}
class Manager : Employee
{
public string Department;
// 자식 클래스의 생성자에서 부모 생성자를 호출하여 필드를 초기화
public Manager(string name, int id, string department) : base(name, id)
{
Department = department;
Console.WriteLine($"[Manager 생성자] 부서: {Department}");
}
}
class Program
{
static void Main()
{
Manager mgr = new Manager("홍길동", 777, "게임개발팀");
}
}
순서를 보면 알겠지만, base(name, id)로 호출된 부모 클래스의 생성자가 먼저 호출된다.
여기서 base()에서 매개 변수로 받는 것은 자식 클래스 생성자에서 매개 변수로 받는 것을 그대로 가져오는 것이다.
이렇게 지워버리면 받아올 수 없기 때문에 오류가 뜨게 된다.
또 다른 예시로는 부모 클래스의 특정 생성자를 사용해야 할 경우가 있다.
위에서 생성자는 오버로딩(Overloading)이 가능하다고 했다. 그렇기 때문에 부모 클래스에서
생성자가 여러개 존재할 수 있고, 이 때는 특정한 생성자를 호출해 주어야 한다.
using System;
class Order
{
public int OrderID;
public string Customer;
// 기본 생성자
public Order()
{
Console.WriteLine("[Order] 일반 주문이 생성되었습니다.");
}
// 매개변수가 있는 생성자
public Order(int orderID, string customer)
{
OrderID = orderID;
Customer = customer;
Console.WriteLine($"[Order] 주문 번호: {OrderID}, 고객: {Customer}");
}
}
class ExpressOrder : Order
{
public string DeliverySpeed;
// 자식 클래스에서 부모 클래스의 특정 생성자 호출
public ExpressOrder(int orderID, string customer, string deliverySpeed)
: base(orderID, customer)
{
DeliverySpeed = deliverySpeed;
Console.WriteLine($"[ExpressOrder] 빠른 배송 속도: {DeliverySpeed}");
}
}
class Program
{
static void Main()
{
ExpressOrder express = new ExpressOrder(1111, "홍길동", "당일 배송");
}
}
또한 부모 클래스가 매개 변수를 필요로 하는, 기본 생성자가 아닌 생성자가 있을 때는 반드시 base를 사용해야 한다.
반대로 base()가 필요 없는 경우는 부모 클래스에 기본 생성자가 있을 경우이다.
기본적으로 명시적으로 호출하지 않아도 자동 호출되기 때문이다.
이런 특성을 이용해서 부모 클래스의 기본값을 설정할 수도 있다.
class Animal
{
public string Species;
public Animal(string species)
{
Species = species;
Console.WriteLine($"Animal 생성됨: {Species}");
}
}
class Dog : Animal
{
public Dog() : base("강아지") // 기본값을 자동으로 설정
{
Console.WriteLine("Dog 생성됨");
}
}
혹은 더 활용하여 this와 base를 함께 사용할 수도 있다.
base()는 부모 클래스의 생성자를 호출하는 것이고, this는 자신의 생성자를 호출하는 것이다.
using System;
class Employee
{
public string Name;
public int ID;
public Employee(string name, int id)
{
Name = name;
ID = id;
Console.WriteLine($"[Employee 생성자] 직원 생성됨: {Name}, ID: {ID}");
}
}
class Manager : Employee
{
public string Department;
// (1) 가장 기본적인 생성자
public Manager() : this("알 수 없음", -1, "미정")
{
Console.WriteLine("[Manager] 기본 생성자 호출됨");
}
// (2) 일부 정보를 입력받는 생성자
public Manager(string name, int id) : this(name, id, "미정")
{
Console.WriteLine("[Manager] 부서 미정인 생성자 호출됨");
}
// (3) 모든 정보를 입력받는 생성자 (최종적으로 base 호출)
public Manager(string name, int id, string department) : base(name, id)
{
Department = department;
Console.WriteLine($"[Manager 생성자] 부서: {Department}");
}
}
class Program
{
static void Main()
{
Manager m1 = new Manager(); // 기본 생성자 호출
Console.WriteLine();
Manager m2 = new Manager("홍길동", 101); // 두 번째 생성자 호출
Console.WriteLine();
Manager m3 = new Manager("김철수", 202, "개발팀"); // 모든 값 지정하는 생성자 호출
}
}