본문 바로가기

Programming

생성자와 접근지정자 : 쉽고 재미있는 C# Programming 의 기본

 

모든 변수는 선언이 되면 초기화 과정을 거칩니다.

객체도 본질적으로는 변수와 같습니다. 객체를 생성할 때 초기화 전용 메서드를 제공합니다.

그것이 바로 생성자(Constructor) 입니다.

 

* 생성자의 이름은 클래스의 이름과 동일하다.

 

생성자는 클래스의 특별한 메서드로, 클래스를 초기화하고 객체를 생성하는 역할을 합니다.

생성자의 이름은 항상 해당 클래스의 이름과 동일합니다. 이것은 클래스를 특정하고 어떤 생성자가 호출되는지를 명확하게 하기 위한 규칙입니다.

 

* 생성자는 반환타입이 없다.

 

생성자는 반환타입을 가질 수 없습니다. 다른 메서드와 달리, 생성자는 객체를 생성하고 초기화하는 역할을 수행하기 때문에 반환값이 필요하지 않습니다. 그러므로 생성자의 선언에서 반환 타입을 지정하지 않습니다.

 

* 생성자는 객체 생성 시 자동으로 호출된다.

 

생성자는 객체가 생성될 때 자동으로 호출되는 특별한 메서드입니다. new 키워드를 사용하여 클래스의 인스턴스를 생성할 때, 해당 클래스의 생성자가 자동으로 호출되어 객체를 초기화합니다. 이로써 객체는 생성됨과 동시에 초기값이 설정되고, 필요한 초기화 작업이 수행됩니다. 생성자의 자동 호출은 객체 지향 프로그래밍에서 객체의 상태를 일관되게 관리하는데 중요한 역할을 합니다.

 

생성자 (Constructor) 는 클래스의 이름과 동일한 메서드로, 객체 생성 시 자동으로 호출되며, 반환 타입이 없어 객체 초기화에 특화된 역할을 수행합니다.


 

1. 개념

 

생성자(Constructor)는 객체 지향 프로그래밍에서 클래스의 인스턴스를 초기화하는 특수한 메서드입니다.

객체를 생성할 때 자동으로 호출되며, 주로 해당 클래스의 필드를 초기화하거나 초기화 코드를 실행하는 데 사용됩니다.

생성자는 클래스의 이름과 동일하며, 반환 유형을 가지지 않습니다.

 

2. 생성자의 형식

 

C# 에서 생성자의 형식은 다음과 같습니다.

class ClassName
{
    // 기본 생성자 (파라미터가 없는 생성자)
    public ClassName()
    {
        // 초기화 코드
    }

    // 매개변수를 받는 생성자
    public ClassName(ParameterType parameter)
    {
        // 초기화 코드
    }

    // 다른 생성자를 호출하는 생성자 (생성자 체이닝)
    public ClassName(ParameterType parameter) : this()
    {
        // 초기화 코드
    }
}

* public : 접근제한자로 생성자를 외부에서 호출할 수 있도록 합니다.

* ClassName : 클래스 이름과 동일한 생성자입니다.

* () : 괄호 안에는 생성자에 전달할 매개변수가 위치합니다.

* : this() : 다른 생성자를 호출하는 생성자를 나타냅니다.

 

3. 생성자의 활용

 

3.1 필드 초기화

 

클래스 내부 필드(멤버 변수)를 초기화하는 것은 생성자에서 주로 이루어집니다. 필드 초기화는 객체가 생성될 때 해당 필드에 처음으로 값을 할당하는 과정을 나타냅니다.

 

아래 예제에서는 생성자를 사용하여 Person 클래스의 name과 age 필드를 초기화하고 있습니다.

public class Person
{
    private string name;
    private int age;

    // 매개변수를 받는 생성자를 사용하여 필드 초기화
    public Person(string personName, int personAge)
    {
        name = personName;
        age = personAge;
    }
}

 

위의 코드에서 name 과 age 필드는 생성자에 전달된 값으로 초기화되고, 객체가 생성될 때 값들이 설정됩니다.

 

3.2 기본값 설정

 

기본 값 설정은 생성자를 사용하여 객체를 생성할 때, 필드에 미리 정의된 기본값을 할당하는 것을 의미합니다.

이는 객체를 생성하고 나서 추가적인 설정 없이도 객체가 기본적으로 유효한 상태로 사용될 수 있도록 하는데 도움이 됩니다.

public class Rectangle
{
    private int width;
    private int height;

    // 기본 생성자를 통한 객체 생성
    public Rectangle()
    {
        // 필드에 기본값 설정
        width = 0;
        height = 0;
    }
}

 

여기서 Rectangle 클래스는 width와 height라는 두 개의 필드를 가지고 있습니다.

기본 생성자(public Rectangle()) 내에서 width와 height에 각각 0을 할당함으로써, 객체를 생성할 때 이 값들이 기본값으로 설정됩니다.

이렇게 기본 값 설정을 사용하면, 개발자가 객체를 생성할 때 명시적으로 초기값을 설정하지 않아도 되므로, 코드 작성과 유지보수가 간편해집니다. 이는 특히 객체의 일부 필드에 대해 항상 동일한 초기값이 필요한 경우에 유용합니다.

 

 3.3 다른 생성자 호출 (생성자 체이닝)

 

생성자 체이닝은 하나의 생성자에서 다른 생성자를 호출하는 개념입니다.

이를 통해 코드 중복을 방지하고 여러 생성자 간에 공통된 초기화 코드를 재사용할 수 있습니다.

 

아래의 예제에서는 Person 클래스의 기본 생성자가 매개변수를 받는 생성자를 호출하고 있습니다.

public class Person
{
    private string name;
    private int age;

    // 기본 생성자에서 다른 생성자 호출 (생성자 체이닝)
    public Person() : this("Unknown", 0)
    {
        // 기본 생성자의 초기화 코드
    }

    // 매개변수를 받는 생성자
    public Person(string personName, int personAge)
    {
        name = personName;
        age = personAge;
    }
}

*this 는 클래스 내에서 현재 객체에 접근하거나 현재 객체의 멤버를 호출할 때 사용됩니다.

 

this("Unknown", 0) 부분은 현재 클래스 내의 다른 생성자를 호출하는 부분입니다. 이것이 생성자 체이닝입니다.

따라서 기본 생성자가 호출되면 내부에서 매개변수를 받는 생성자가 호출되어 "Unknown"0으로 초기화됩니다.

 

3.4 상속과 다형성 지원

 

생성자는 클래스의 상속 구조에서 부모 클래스의 생성자를 호출하거나 인터페이스의 구현을 지원하는 등의 작업에 사용됩니다.

 

public class Square : Rectangle
{
    // Square 클래스의 생성자에서 부모 클래스(Rectangle)의 생성자 호출
    public Square(int sideLength) : base(sideLength, sideLength)
    {
        // 추가적인 초기화 코드
    }
}

 

3.4.1 상속에서 생성자의 활용

 

부모 클래스의 생성자는 실제로 상속은 되지만, 특정 상황에서는 부모 클래스의 생성자를 명시적으로 호출해야 합니다. 이는 부모 클래스가 매개변수가 있는 생성자를 가지고 있을 때 발생합니다.

 

생성자는 상속되지만, 자식 클래스의 생성자에서 부모 클래스의 생성자를 명시적으로 호출하지 않으면 컴파일러가 자동으로 부모 클래스의 기본 생성자를 호출하게 됩니다. 그러나 부모 클래스에 매개변수가 있는 생성자가 정의되어 있을 경우, 이 기본 생성자는 제공되지 않습니다.

 

따라서 자식 클래스에서 부모 클래스의 매개변수가 있는 생성자를 호출하려면 명시적으로 해주어야 합니다.

public class Animal
{
    // 부모 클래스의 생성자
    public Animal(string name)
    {
        Console.WriteLine($"Animal constructor called with name: {name}");
    }
}

public class Dog : Animal
{
    // 자식 클래스의 생성자
    public Dog(string name) : base(name)
    {
        Console.WriteLine("Dog constructor called");
    }
}

 

위의 예제에서 Dog 클래스는 Animal 클래스를 상속받고 있습니다. Dog 클래스의 생성자에서는 base(name)을 통해 부모 클래스의 생성자를 명시적으로 호출하고 있습니다. 이렇게 함으로써 부모 클래스의 생성자가 실행되면서 초기화 작업이 수행됩니다.

 

[ 위 코드를 사용한 예 ]

class Program
{
    static void Main()
    {
        // Dog 클래스의 인스턴스를 생성
        Dog myDog = new Dog("Buddy");
    }
}

 

위 예제에서 Dog 클래스의 인스턴스를 생성할 때 "Buddy"라는 이름을 인자로 전달합니다. 이 생성자 호출은 다음과 같은 순서로 진행됩니다.

 

  1. Dog 클래스의 생성자가 호출되면서 "Buddy"를 인자로 받습니다.
  2. Dog 클래스의 생성자 내부에서 base(name)을 통해 부모 클래스인 Animal 클래스의 생성자를 호출합니다.
  3. Animal 클래스의 생성자 내부에서 동물의 이름을 출력하면서 객체가 초기화됩니다.
  4. Dog 클래스의 생성자 내부에서 "Dog constructor called"를 출력합니다.
Animal constructor called with name: Buddy
Dog constructor called

 

상속 관계에서는 부모 클래스의 생성자를 호출하여 부모 클래스의 초기화 작업을 수행하고, 그 후에 자식 클래스의 생성자가 추가적인 초기화 작업을 수행하는 구조를 가집니다.

 

 

이렇게 생성자를 활용하여 객체의 초기화와 다양한 작업을 수행함으로써 안정적이고 일관된 객체의 상태를 유지하고, 코드의 가독성과 유지보수성을 향상시킬 수 있습니다.


접근 지정자(access modifier)는 클래스의 멤버(필드, 메서드, 속성 등)가 외부에서 접근될 수 있는 범위를 지정하는 데 사용됩니다. C#에서는 다양한 접근 지정자가 제공되며, 이를 통해 코드의 캡슐화(encapsulation)와 보안을 유지하고, 코드의 유지보수성을 향상시킬 수 있습니다.

 

1. public

  • 가장 넓은 범위의 접근 지정자입니다. 해당 멤버는 외부의 모든 코드에서 접근 가능합니다.
  • 다른 어셈블리(assembly)에서도 접근 가능하도록 하려면 public으로 지정해야 합니다.
public class MyClass
{
    public int PublicField;
    public void PublicMethod() { }
}

 

* 어셈블리 : 일반적으로 하나의 프로젝트 또는 솔루션 내에서 생성된 DLL 또는 EXE 파일을 나타냅니다. 따라서 "다른 어셈블리"는 다른 프로그램이나 라이브러리를 의미합니다.

 

2. private

 

  • 가장 제한적인 범위의 접근 지정자입니다. 해당 멤버는 선언된 클래스 내부에서만 접근 가능하며, 외부에서는 접근할 수 없습니다
public class MyClass
{
    private int PrivateField;
    private void PrivateMethod() { }
}

 

3. prtected

  • 클래스 내부 및 해당 클래스를 상속받은 파생 클래스에서만 접근 가능합니다.
  • 외부에서는 접근할 수 없지만, 파생 클래스에서는 해당 멤버에 접근할 수 있습니다.
public class MyBaseClass
{
    protected int ProtectedField;
}

public class MyDerivedClass : MyBaseClass
{
    public void AccessProtectedField()
    {
        // MyBaseClass의 ProtectedField에 접근 가능
        ProtectedField = 10;
    }
}

 

4. internal

  • 같은 어셈블리 내에서만 접근 가능합니다. 다른 어셈블리에서는 접근할 수 없습니다.
  • internal로 지정된 멤버는 같은 프로젝트 내에서는 자유롭게 접근할 수 있습니다.
internal class MyInternalClass
{
    internal int InternalField;
}

 

이러한 접근 지정자들은 클래스의 멤버뿐만 아니라 클래스 자체에도 적용됩니다.

클래스에 대한 접근 지정자를 사용하면 해당 클래스가 다른 코드에서 어떻게 사용되는지를 조절할 수 있습니다.

이를 통해 코드의 유연성과 보안을 유지하는 데 도움이 됩니다.

 

C#에서 클래스나 멤버를 선언할 때 명시적인 접근 지정자를 사용하지 않으면 클래스는 기본적으로 internal 로 간주되고 멤버변수, 메서드, 속성등은 기본적으로 private로 간주됩니다.

 

이는 C#  언어의 규칙입니다. 명시적인 접근 지정자를 사용해서 코드의 가시성을 명확히 하는것이 좋습니다.