[로봇활용_9주차] C# 중첩 클래스(Nested Class)

최윤호·2025년 10월 8일
post-thumbnail

중첩 클래스란?

코드를 작성하다 보면 "이 클래스는 오직 저 클래스 안에서만 쓰이는데,
굳이 별도 파일로 분리해야 하나?" 하는 생각이 들 때가 있습니다.
마치 중요한 서류에 필요한 자료를 스테이플러로 함께 묶어두고 싶은 마음처럼요.
이럴 때 사용할 수 있는 기능이 바로 중첩 클래스(Nested Class)입니다.
이름 그대로 클래스 안에 또 다른 클래스를 정의하는 방식이죠.
이번 글에서는 중첩 클래스(Nested Class)에 대해 알아보겠습니다!

1)기본 구조

중첩 클래스는 다른 클래스(또는 구조체)의 내부에 선언된 클래스를 말합니다.
바깥쪽 클래스를 외부 클래스(Outer Class),
안쪽 클래스를 내부 클래스(Inner Class)라고 부릅니다.
구조는 직관적입니다. 그냥 클래스{} 안에서 또 다른 클래스를 선언하면 됩니다.

// 1. 외부 클래스 (Outer Class)
public class Car
{
    // Car 클래스의 멤버 (필드, 메서드 등)
    private int _fuelLevel;

    public void AddFuel(int amount)
    {
        _fuelLevel += amount;
        Console.WriteLine($"연료 {amount}L 주입. 현재 연료: {_fuelLevel}L");
    }

    // 2. 내부 클래스 (Inner/Nested Class)
    public class Engine
    {
        public void Start()
        {
            Console.WriteLine("엔진 시동을 겁니다.");
            // ... 엔진 관련 로직 ...
        }
    }
}

2)중첩 클래스를 사용하는 이유

중첩 클래스는 다음과 같은 이점을 제공합니다.

1. 강력한 캡슐화와 논리적 그룹화
하나의 클래스가 다른 클래스와 긴밀하게 연결되어 있고,
오직 그 클래스에서만 사용될 때 중첩 클래스는 빛을 발합니다.
코드의 논리적 구조를 명확하게 하고, 불필요한 클래스가
외부로 노출되는 것을 막아 캡슐화를 강화합니다.

비유: 자동차와 엔진
엔진(Engine)자동차(Car)의 핵심 부품이지만,
우리는 자동차를 운전할 때 엔진을 직접 만지지 않습니다.
엔진은 자동차라는 더 큰 개념 안에서만 의미를 가지며, 독립적으로 존재하지 않습니다.

2. 외부 클래스의 private 멤버 접근 가능
이것이 중첩 클래스의 가장 특별한 능력입니다.
내부 클래스는 자신을 감싸는 외부 클래스의 private멤버에도 접근할 수 있습니다!
일반적인 클래스라면 private멤버는 절대 외부에서 접근할 수 없지만,
중첩 클래스는 '가족'으로 취급되어 비밀스러운 정보까지 공유할 수 있는 셈이죠.
단, 중첩 클래스라고 해서 "자동으로 외부 인스턴스를 품고 있는 것"은 아닙니다.
어떤 Car에 속한 엔진인지 알기 위해 생성자 등으로 Car인스턴스를 따로 넘겨줘야 합니다.

3)사용법

Engine클래스가 Car클래스의 private필드 _fuelLevel에 접근하여
시동을 거는 예제를 만들어 보겠습니다. 여기서 Engine객체를 만들 때,
자신을 소유한 Car객체의 참조를 넘겨주는 것이 일반적입니다.

[코드]

using System;

public class Car
{
    private int _fuelLevel = 0;
    private bool _isEngineOn = false;

    public void AddFuel(int amount)
    {
        if (amount > 0)
        {
            _fuelLevel += amount;
            Console.WriteLine($"연료 {amount}L 주입. 현재 연료: {_fuelLevel}L");
        }
    }

    // Engine 클래스는 Car의 상태를 직접 조작할 수 있습니다.
    public class Engine
    {
        // 어떤 Car 인스턴스에 속해있는지 저장할 필드
        private Car _ownerCar;

        // 생성자를 통해 자신을 소유한 Car 객체를 전달받음
        public Engine(Car owner)
        {
            _ownerCar = owner;
        }

        public void Start()
        {
            // 외부 클래스의 private 필드에 접근!
            if (_ownerCar._fuelLevel <= 0)
            {
                Console.WriteLine("연료 부족! 시동을 걸 수 없습니다.");
                return;
            }

            // 외부 클래스의 private 필드를 변경!
            _ownerCar._isEngineOn = true;
            Console.WriteLine("부르릉... 엔진 시동 성공!");
        }
    }

    // Car 클래스에서 자신의 Engine을 사용하는 메서드
    public void StartCar()
    {
        // Engine 객체를 생성할 때, 'this'(Car 객체 자신)를 넘겨줌
        Engine carEngine = new Engine(this);
        carEngine.Start();
    }
}

class Program
{
    static void Main()
    {
        Car myBmw = new Car();

        myBmw.StartCar(); // 연료가 없어서 시동 실패
        myBmw.AddFuel(50); // 연료 주입
        myBmw.StartCar(); // 시동 성공!
    }
}

[실행 결과]

연료 부족! 시동을 걸 수 없습니다.
연료 50L 주입. 현재 연료: 50L
부르릉... 엔진 시동 성공!

외부에서 중첩 클래스를 사용할 때는 외부 클래스.내부 클래스형태로 사용합니다.

[예시]

class Program
{
    static void Main()
    {
        Car myCar = new Car();

        // 외부에서는 '외부 클래스 이름.내부 클래스 이름'형태로 중첩 클래스 사용
        Car.Engine engine = new Car.Engine(myCar);

        myCar.AddFuel(30);
        engine.Start();
    }
}

4)요약

중첩 클래스를 적절한 상황에 사용하면 코드의 품질을 한 단계 높일 수 있습니다.

특징설명
논리적 그룹화특정 클래스에서만 사용되는 클래스를 내부에 묶어 관리
강력한 캡슐화외부에는 불필요한 클래스 노출을 최소화
Private 접근외부 클래스의 private 멤버에 접근하여 긴밀한 상호작용 가능
주의 사항과도한 중첩은 가독성을 해칠 수 있으므로, 필요한 경우 1~2단계로만 사용 권장
profile
🚀 미래의 엔지니어를 꿈꾸는 훈련생의 기록 📝

0개의 댓글