Devin.KR

Visual Basic · 기본

Visual Basic과 .NET 입문

클래스와 속성 - 비품을 객체로

Class·Property·자동 속성, New 생성자, Shared 멤버, Nothing

개발자KR · 원고 갱신

이 장에서 배우는 것

앞 장에서 배열과 문자열을 이용해 여러 비품의 정보를 다루었다. 비품 이름을 담은 배열과 대여 여부를 담은 배열을 따로 만들면, 같은 위치의 값이 같은 비품을 뜻하도록 계속 맞춰야 한다. 이번에는 비품 하나의 정보와 동작을 한곳에 묶는다. 노트북 한 대를 나타내는 값을 만들고, 그 값에 이름을 묻거나 대여를 요청하는 방식으로 프로그램을 바꾼다.

클래스(class)는 어떤 정보를 보관하고 어떤 동작을 제공할지 정하는 형식이다. 객체(object)는 그 형식으로 만들어 실제로 사용하는 대상이다. 이 장에서는 비품 클래스를 정의한 뒤 객체 두 개를 만들고, 대여와 반납에 따라 각 객체의 상태가 달라지는 과정을 확인한다.

  • Class로 비품의 정보와 동작을 묶는 사용자 정의 형식을 만든다.
  • Property와 자동 속성으로 정보를 읽고 쓰는 통로를 만든다.
  • New 생성자로 객체의 시작 상태를 정한다.
  • Shared 멤버로 모든 비품이 함께 사용하는 생성 수를 관리한다.
  • Nothing과 객체 참조를 구별하고, 객체가 없는 경우를 확인한다.

문제 상황

작은 사무실에서 노트북과 프로젝터를 함께 사용한다. 담당자는 비품 번호, 이름, 보관 위치, 대여 여부를 기록한다. 노트북을 빌리면 노트북의 대여 여부만 바뀌어야 한다. 이미 대여 중인 비품에 다시 대여 요청이 들어오면 요청을 거절해야 한다. 반납하면 같은 비품이 다시 대여 가능 상태가 되어야 한다.

이 정보를 각각의 배열로 관리한다고 생각해 보자. 첫 번째 이름이 노트북이라면 첫 번째 비품 번호와 첫 번째 대여 여부도 노트북의 정보여야 한다. 이름 배열만 순서를 바꾸면 비품 번호와 대여 상태가 다른 비품에 연결될 수 있다. 배열 자체의 문제가 아니라, 하나의 비품에 속하는 정보를 여러 곳에서 따로 다루는 방식의 문제다.

비품 객체를 만들면 번호, 이름, 위치, 대여 상태가 한 대상에 모인다. 객체를 배열에 넣어도 각 객체가 자신의 정보를 유지한다. 또한 대여 상태를 외부에서 마음대로 바꾸게 하지 않고, 대여 요청을 처리하는 함수가 상태를 바꾸도록 만들 수 있다. 정보가 모이는 것과 상태를 바꾸는 규칙이 모이는 것이 함께 이루어진다.

이 장의 프로그램은 입력을 기다리지 않는다. 정해진 순서대로 비품을 만들고 대여와 반납을 수행한다. 실행할 때마다 같은 결과가 나오므로 객체의 상태 변화를 출력과 나란히 확인할 수 있다.

클래스는 설계이고 객체는 실제 비품이다

Class Equipment와 End Class 사이에 비품 형식의 내용을 적는다. 여기서 Equipment는 직접 정한 형식 이름이다. String이나 Integer를 변수의 형식으로 쓰듯이, 정의한 뒤에는 Equipment도 변수의 형식으로 사용할 수 있다.

클래스 안에 선언한 변수, 속성, 프로시저를 멤버(member)라고 한다. 그중 객체가 내부 정보를 보관하는 변수는 필드(field)라고 부른다. 이번 비품 클래스는 이름과 대여 상태를 필드에 보관한다. 외부에서는 필드를 직접 만지는 대신 속성과 프로시저를 사용한다.

Public Class Equipment
    Private _name As String = "이름 없음"
    Private _isLoaned As Boolean = False
End Class

Public은 여기서 프로그램의 다른 코드가 해당 형식이나 멤버를 사용할 수 있다는 뜻이다. Private은 그 멤버를 선언한 클래스 내부에서만 사용할 수 있다는 뜻이다. 밑줄로 시작하는 필드 이름은 내부 저장 공간임을 구별하려고 선택한 작성 관례다. Visual Basic 문법이 밑줄을 요구하는 것은 아니다.

클래스를 선언했다고 비품 객체가 만들어지는 것은 아니다. 다음 문장에서 As Equipment는 변수의 형식을 정하고, New Equipment(...)는 실제 객체를 만든다. 괄호 안의 값은 잠시 뒤 살펴볼 생성자에 전달한다.

Dim laptop As Equipment =
    New Equipment("EQ-101", "업무용 노트북", "보관장 A")

클래스로 만든 각각의 객체를 인스턴스(instance)라고도 한다. 같은 클래스로 노트북과 프로젝터를 만들더라도 두 객체의 이름과 대여 상태는 각각 보관된다. 노트북을 대여했다고 프로젝터까지 대여 상태가 되는 것은 아니다.

하나의 비품 클래스로 만든 두 객체는 각자의 정보와 대여 상태를 가진다
클래스 정의와 객체 생성의 역할
구분코드에서의 모습역할
클래스Class Equipment비품이 제공할 정보와 동작을 정의한다.
객체 생성New Equipment(...)정의에 따라 새 비품 객체를 만든다.
객체 변수laptop As Equipment비품 객체를 가리키는 값을 보관한다.
객체별 필드_isLoaned각 비품의 대여 상태를 따로 보관한다.

속성과 생성자로 비품의 상태를 정한다

속성은 정보를 읽고 쓰는 통로다

속성(property)은 객체의 정보를 읽거나 설정하는 멤버다. 사용하는 쪽에서는 laptop.Name처럼 객체 이름 뒤에 점과 속성 이름을 적는다. 값을 읽을 때는 Get 부분이 실행되고, 값을 대입할 때는 Set 부분이 실행된다.

Public Property Name As String
    Get
        Return _name
    End Get
    Set(value As String)
        If value Is Nothing Then
            _name = "이름 없음"
        Else
            Dim cleaned As String = value.Trim()
            If cleaned.Length = 0 Then
                _name = "이름 없음"
            Else
                _name = cleaned
            End If
        End If
    End Set
End Property

Get은 내부 필드 _name의 값을 반환한다. Set의 매개변수 value에는 새로 대입한 값이 들어온다. 예를 들어 laptop.Name = "회의용 노트북"을 실행하면 value가 그 문자열을 받는다.

이 속성은 이름 앞뒤의 공백을 제거한다. 공백만 입력했거나 문자열이 없는 경우에는 “이름 없음”을 저장한다. Nothing인 문자열에는 Trim()을 호출할 수 없으므로 먼저 확인한다. 이름을 여러 곳에서 바꾸더라도 이 속성을 거치면 같은 규칙이 적용된다.

필드를 숨기고 공개된 통로로 정보를 다루게 하는 방식을 캡슐화(encapsulation)라고 한다. 여기서는 이름을 정리하는 규칙과 대여 상태를 바꾸는 규칙을 클래스 안에 모으는 것으로 이해하면 된다. 단순히 필드 앞에 Private을 붙이는 것뿐 아니라, 어떤 통로로 어떤 변경을 허용할지도 정한다.

자동 속성과 읽기 전용 속성

값을 저장하고 읽는 것 외에 별도 처리가 필요 없다면 자동 속성을 사용할 수 있다. 자동 속성(auto-implemented property)은 저장용 필드를 컴파일러가 마련해 주는 속성이다. 컴파일러는 소스 코드를 실행 가능한 형태로 변환하는 도구다. 자동 속성에는 직접 Get과 Set을 작성하지 않는다.

Public Property Location As String

보관 위치는 이번 예제에서 특별한 처리 없이 읽고 쓴다. 반면 이름은 공백을 정리해야 하므로 직접 작성한 속성을 사용한다. 자동 속성도 속성이지만, 이 선언만으로 입력값 검사나 문자열 정리가 추가되지는 않는다.

비품 번호는 생성할 때 정하고 이후에는 바꾸지 않기로 한다. 다음 읽기 전용 자동 속성은 값을 읽는 용도로 공개한다. 이 클래스의 생성자에서는 초기값을 대입할 수 있다.

Public ReadOnly Property AssetCode As String

대여 여부도 외부에서 읽기만 허용한다. 다만 클래스의 대여 함수와 반납 프로시저가 내부 필드를 바꿔야 하므로, 필드를 반환하는 읽기 전용 속성으로 작성한다.

Public ReadOnly Property IsLoaned As Boolean
    Get
        Return _isLoaned
    End Get
End Property

읽기 전용이라는 말은 사용하는 쪽에서 그 속성에 대입할 수 없다는 뜻이다. 객체 내부의 상태까지 고정된다는 뜻은 아니다. IsLoaned가 반환하는 값은 대여와 반납에 따라 달라진다.

생성자는 객체의 시작 상태를 만든다

생성자(constructor)는 객체가 만들어질 때 실행되는 특별한 프로시저다. Visual Basic에서는 Sub New로 작성한다. 일반적인 Sub처럼 매개변수를 받을 수 있으며, 반환값을 선언하지 않는다.

Public Sub New(assetCode As String,
               name As String,
               location As String)
    Me.AssetCode = assetCode
    Me.Name = name
    Me.Location = location
    _createdCount += 1
End Sub

Me는 지금 생성하거나 처리하고 있는 객체 자신을 뜻한다. Me.Name = name에서 왼쪽은 객체의 속성이고 오른쪽은 생성자 매개변수다. Visual Basic은 대소문자로 이름을 구별하지 않으므로, 여기서는 Me.가 두 이름의 역할을 분명히 한다.

생성자에서 Name 속성에 대입하면 앞서 작성한 Set도 실행된다. 내부 필드에 바로 대입하는 대신 속성을 거쳐 처음 입력한 이름에도 같은 정리 규칙을 적용한다. 대여 상태는 필드 선언에서 False로 시작하므로 새 비품은 대여 가능 상태다.

이 생성자는 비품 번호, 이름, 보관 위치의 세 인수를 요구한다. 완성 코드에는 인수 없는 생성자를 따로 작성하지 않는다. 따라서 객체를 만들 때 세 값을 모두 전달해야 한다. 이번 프로그램의 비품 번호와 위치는 정해진 문자열을 사용하며, 중복 번호 검사 같은 별도 업무 규칙은 구현하지 않는다.

객체 참조, Nothing, Shared를 구별한다

클래스는 참조 형식(reference type)이다. 클래스 형식의 변수에는 객체 자체의 모든 정보가 들어가는 대신, 어떤 객체를 가리키는지 나타내는 참조(reference)가 들어간다. 변수에 다른 객체 변수를 대입하면 같은 객체를 가리키게 된다.

Dim sameLaptop As Equipment = laptop
sameLaptop.Location = "회의실 선반"

이 코드는 노트북을 하나 더 만들지 않는다. sameLaptop과 laptop이 같은 노트북을 가리킨다. 따라서 sameLaptop으로 위치를 바꾸면 laptop.Location을 읽어도 “회의실 선반”이 나온다. 새 객체가 필요할 때 사용하는 표현은 New Equipment(...)다.

Nothing은 형식에 따른 기본값을 나타낸다. 특히 클래스 형식의 변수에 저장된 Nothing은 가리키는 객체가 없다는 뜻이다. Dim missing As Equipment = Nothing은 이름이 빈 비품을 만드는 코드가 아니다. 객체를 만들지 않은 변수다.

객체가 없는 변수로 속성이나 메서드를 사용하려 하면 실행 중 오류가 발생한다. 메서드(method)는 클래스 안에 정의한 동작 프로시저를 뜻한다. 사용 전에 Is Nothing 또는 IsNot Nothing으로 객체가 있는지 확인한다. Nothing을 숫자나 논리값에 사용할 때의 의미까지 “객체 없음”으로 일반화해서는 안 된다.

If missing Is Nothing Then
    Console.WriteLine("선택된 비품이 없다.")
End If
두 변수는 같은 객체를 가리킬 수 있으며 Nothing인 변수는 객체를 가리키지 않는다

객체별 정보와 달리 클래스 전체에서 함께 사용할 정보도 있다. 공유 멤버(shared member)는 Shared를 붙여 선언하며, 각 객체마다 따로 생기지 않는다. 이번에는 비품 객체를 만든 누적 수를 공유 필드에 저장한다.

Private Shared _createdCount As Integer = 0

Public Shared ReadOnly Property TotalCreated As Integer
    Get
        Return _createdCount
    End Get
End Property

생성자가 한 번 실행될 때마다 _createdCount를 1 증가시킨다. 노트북과 프로젝터를 만들면 값은 2가 된다. TotalCreated는 Equipment.TotalCreated처럼 클래스 이름으로 읽는다. 특정 비품의 수가 아니라 클래스에서 함께 관리하는 수이기 때문이다.

이 값은 현재 대여 중인 수나 현재 사용 가능한 수가 아니다. 이 프로그램 실행 중 생성자가 호출된 횟수다. 기존 객체를 다른 변수에 대입하거나 변수에 Nothing을 대입해도 생성 수를 바꾸지 않는다. 실행을 다시 시작하면 공유 필드도 다시 0에서 시작한다.

완성 코드

dotnet new console -lang VB로 만든 .NET 10 콘솔 프로젝트의 Program.vb를 다음 내용으로 바꾼다. 클래스와 시작 모듈을 한 파일에 작성한다. Option Strict On은 형식이 맞지 않는 값을 암시적으로 변환하는 일을 제한한다. 여기서는 사용하는 변수와 매개변수의 형식을 모두 명시한다.

Option Strict On
Option Explicit On

Imports System

Public Class Equipment
    Private _name As String = "이름 없음"
    Private _isLoaned As Boolean = False
    Private Shared _createdCount As Integer = 0

    Public ReadOnly Property AssetCode As String
    Public Property Location As String

    Public Property Name As String
        Get
            Return _name
        End Get
        Set(value As String)
            If value Is Nothing Then
                _name = "이름 없음"
            Else
                Dim cleaned As String = value.Trim()
                If cleaned.Length = 0 Then
                    _name = "이름 없음"
                Else
                    _name = cleaned
                End If
            End If
        End Set
    End Property

    Public ReadOnly Property IsLoaned As Boolean
        Get
            Return _isLoaned
        End Get
    End Property

    Public Shared ReadOnly Property TotalCreated As Integer
        Get
            Return _createdCount
        End Get
    End Property

    Public Sub New(assetCode As String,
                   name As String,
                   location As String)
        Me.AssetCode = assetCode
        Me.Name = name
        Me.Location = location
        _createdCount += 1
    End Sub

    Public Function TryBorrow() As Boolean
        If _isLoaned Then
            Return False
        End If

        _isLoaned = True
        Return True
    End Function

    Public Sub ReturnItem()
        _isLoaned = False
    End Sub
End Class

Module Program
    Sub Main()
        Dim laptop As Equipment =
            New Equipment("EQ-101", "  업무용 노트북  ", "보관장 A")
        Dim projector As Equipment =
            New Equipment("EQ-102", "회의용 프로젝터", "보관장 B")

        Console.WriteLine($"생성한 비품 수: {Equipment.TotalCreated}")

        Dim items As Equipment() = {laptop, projector}
        For Each item As Equipment In items
            Console.WriteLine(
                $"{item.AssetCode} | {item.Name} | {item.Location}")
        Next

        If laptop.TryBorrow() Then
            Console.WriteLine("노트북 첫 대여: 성공")
        End If

        If Not laptop.TryBorrow() Then
            Console.WriteLine("노트북 재대여: 거절")
        End If

        Dim sameLaptop As Equipment = laptop
        sameLaptop.Location = "회의실 선반"
        Console.WriteLine($"노트북 보관 위치: {laptop.Location}")

        If laptop.IsLoaned Then
            Console.WriteLine("노트북 상태: 대여 중")
        End If

        If Not projector.IsLoaned Then
            Console.WriteLine("프로젝터 상태: 대여 가능")
        End If

        laptop.ReturnItem()
        If Not laptop.IsLoaned Then
            Console.WriteLine("노트북 반납 후: 대여 가능")
        End If

        laptop.Name = "   "
        Console.WriteLine($"빈 이름 처리: {laptop.Name}")

        Dim missing As Equipment = Nothing
        If missing Is Nothing Then
            Console.WriteLine("선택된 비품이 없다.")
        End If

        Console.WriteLine($"마지막 생성 수: {Equipment.TotalCreated}")
    End Sub
End Module

줄별 해설

Option Strict On과 Option Explicit On은 파일의 처음에 둔다. 뒤의 옵션은 변수를 선언한 뒤 사용하게 한다. Imports System은 Console 같은 이름을 짧게 사용할 수 있게 한다.

Public Class Equipment는 비품 형식의 시작이다. _name과 _isLoaned는 객체마다 따로 존재하고, _createdCount는 Shared이므로 클래스에서 함께 사용한다. 이름은 “이름 없음”, 대여 상태는 False, 생성 수는 0에서 시작한다.

AssetCode는 읽기 전용 자동 속성이다. 생성자가 번호를 정한 뒤 호출하는 코드에서는 읽기만 한다. Location은 읽고 쓸 수 있는 자동 속성이다. 두 선언 모두 명시적인 저장 필드를 작성하지 않는다.

Name은 직접 작성한 속성이다. 읽을 때 _name을 반환하고, 쓸 때 전달받은 문자열을 확인한다. Nothing이면 대체 이름을 저장한다. 그렇지 않으면 Trim()으로 앞뒤 공백을 제거한 문자열을 지역 변수 cleaned에 보관한다. 그 길이가 0이면 역시 대체 이름을 저장한다.

IsLoaned는 _isLoaned를 읽는 통로다. Set이 없고 ReadOnly를 붙였으므로 laptop.IsLoaned = True와 같은 대입은 허용하지 않는다. TotalCreated도 읽기 전용이지만 공유 속성이므로 클래스 이름으로 접근한다.

Sub New는 세 인수를 받아 각 속성에 대입한다. 노트북 이름에는 앞뒤 공백이 들어 있지만 Name 속성을 거치면서 제거된다. 마지막 줄은 생성 수를 증가시킨다. 객체를 두 번 만들면 이 줄도 두 번 실행된다.

TryBorrow는 대여 요청을 처리하는 함수다. 이미 대여 중이면 상태를 바꾸지 않고 False를 반환한다. 대여 가능하면 내부 필드를 True로 바꾸고 True를 반환한다. 반환값은 요청의 성공 여부이며, 속성 IsLoaned는 현재 상태다. 두 값의 역할을 구별해야 한다.

ReturnItem은 대여 상태를 False로 만든다. 이번 업무 규칙에서는 이미 반납된 비품에 다시 호출해도 대여 가능 상태를 유지한다. 반납 성공 여부를 따로 반환하지 않으므로 Function이 아닌 Sub로 작성했다.

Module Program의 Sub Main에서 프로그램을 시작한다. 노트북과 프로젝터를 생성하고 공유 속성으로 생성 수를 출력한다. items는 앞 장에서 다룬 배열이며, 각 요소의 형식이 Equipment다. 배열에는 이미 만든 두 객체의 참조가 들어간다. 배열을 만드는 과정에서 비품 생성자가 다시 실행되지는 않는다.

For Each는 배열의 객체를 하나씩 item으로 받아 번호, 이름, 위치를 출력한다. 이어서 같은 노트북에 대여를 두 번 요청한다. 첫 요청은 성공하고 두 번째 요청은 거절된다. 프로젝터에는 대여 요청을 하지 않았으므로 대여 가능 상태를 유지한다.

sameLaptop에는 laptop의 참조를 대입한다. 이 변수로 위치를 바꾼 뒤 원래 변수로 읽어 변경 결과를 확인한다. 반납 후에는 노트북의 대여 상태가 다시 False인지 확인한다.

끝부분은 공백 이름과 객체 없는 변수를 확인한다. 공백 이름은 속성의 규칙에 따라 “이름 없음”으로 바뀐다. missing에는 객체가 없으므로 속성을 읽지 않고 안내 문장만 출력한다. 마지막 생성 수는 여전히 2다.

실행 결과

터미널에서 다음 명령을 순서대로 실행한다. 프로젝트를 만든 뒤 실행하기 전에 위 완성 코드로 Program.vb를 교체한다.

dotnet new console -lang VB -f net10.0 -n OfficeEquipment
cd OfficeEquipment
dotnet run

프로그램의 예상 출력은 다음과 같다. 날짜, 사용자 입력, 임의의 값에 의존하지 않으므로 같은 코드의 출력은 동일하다.

생성한 비품 수: 2
EQ-101 | 업무용 노트북 | 보관장 A
EQ-102 | 회의용 프로젝터 | 보관장 B
노트북 첫 대여: 성공
노트북 재대여: 거절
노트북 보관 위치: 회의실 선반
노트북 상태: 대여 중
프로젝터 상태: 대여 가능
노트북 반납 후: 대여 가능
빈 이름 처리: 이름 없음
선택된 비품이 없다.
마지막 생성 수: 2

실무에서 자주 틀리는 것

형식만 선언하고 객체를 만들었다고 생각한다

다음 변수에는 비품 객체가 없다. As Equipment는 형식을 정할 뿐이다. 객체가 없는 상태에서 이름을 읽으면 실행 중 오류가 발생한다.

Dim item As Equipment = Nothing
Console.WriteLine(item.Name)

새 비품을 사용할 상황이라면 생성자를 호출한다. 이 클래스는 세 인수를 받는 생성자를 제공하므로 필요한 값을 함께 전달한다.

Dim item As Equipment =
    New Equipment("EQ-103", "예비 노트북", "보관장 C")
Console.WriteLine(item.Name)

반대로 아직 선택된 비품이 없다는 상태를 표현하려면 Nothing을 유지하고, 사용 전에 확인한다. 없는 객체를 임의로 만드는 것이 항상 올바른 해결은 아니다.

속성 안에서 같은 속성에 다시 대입한다

다음 Set은 자기 자신을 다시 호출한다. 새 값을 저장하는 대신 같은 호출을 반복하게 된다.

Public Property Name As String
    Get
        Return _name
    End Get
    Set(value As String)
        Name = value
    End Set
End Property

실제로 값을 보관할 대상은 필드다. 아래는 저장 위치만 바로잡은 형태이며, 완성 코드에서는 여기에 이름 정리 규칙도 넣었다.

Public Property Name As String
    Get
        Return _name
    End Get
    Set(value As String)
        _name = value
    End Set
End Property

비품별 상태에 Shared를 붙인다

대여 상태가 공유 필드이면 한 객체의 대여 상태를 바꿀 때 다른 객체도 같은 필드 값을 읽는다. 비품마다 다른 상태가 필요한 요구와 맞지 않는다.

Private Shared _isLoaned As Boolean = False

대여 상태에서는 Shared를 제거한다. 생성 수처럼 클래스 전체에서 함께 관리할 값에만 공유 선언을 사용한다.

Private _isLoaned As Boolean = False
Private Shared _createdCount As Integer = 0

객체 변수의 대입을 독립적인 복사로 생각한다

다음 코드를 작성하고 spare의 위치만 바뀔 것이라고 예상하면 문제가 생긴다. 두 변수는 같은 객체를 가리키므로 laptop으로 읽는 위치도 바뀐다.

Dim spare As Equipment = laptop
spare.Location = "별도 보관장"

독립적인 예비 비품이 필요한 상황이라면 새로운 번호와 정보로 별도 객체를 만든다. 기존 객체를 복제하는 기능을 구현한 것은 아니며, 새로운 비품을 등록한 것이다.

Dim spare As Equipment =
    New Equipment("EQ-104", "예비 노트북", "별도 보관장")

이 경우 생성 수도 1 증가한다. 새 객체인지 같은 객체의 다른 참조인지에 따라 상태 변경과 생성 수의 결과가 달라진다.

한눈에 보기

비품 클래스에 사용한 문법과 선택 기준
문법의미비품 예제확인할 점
Class사용자 정의 형식Equipment정의만으로 객체가 생기지 않는다.
Private 필드내부 저장 공간_isLoaned공개된 동작으로 변경하게 한다.
Property읽기와 쓰기 통로Name별도 처리에는 Get과 Set을 작성한다.
자동 속성저장 공간을 자동으로 마련Location선언만으로 값 검사 규칙이 생기지 않는다.
ReadOnly호출하는 쪽의 대입 제한IsLoaned반환되는 상태가 항상 고정되지는 않는다.
Sub New생성 시 초기화번호·이름·위치 설정정의한 매개변수에 맞게 인수를 전달한다.
Shared클래스에서 함께 사용TotalCreated클래스 이름으로 접근한다.
Nothing형식에 따른 기본값객체가 없는 비품 변수참조 형식에서는 사용 전에 객체 유무를 확인한다.

객체의 정보를 읽는 일, 새 객체를 만드는 일, 같은 객체를 다른 변수로 가리키는 일을 구별하면 코드의 결과를 예측하기 쉬워진다. 이번 클래스에서는 비품별 상태를 객체에 두고, 누적 생성 수만 클래스에 두었다. 다음의 상속과 인터페이스를 살펴보기 전에 이 구분과 속성의 역할을 익혀 둔다.

연습 문제

  1. 완성 코드에서 노트북 생성자의 이름 인수를 " "으로 바꾸었다. 배열을 출력할 때 노트북 이름은 무엇인가. 생성자와 속성 사이의 실행 순서를 설명한다.

  2. 완성 코드의 sameLaptop.Location 대입 바로 다음에 sameLaptop.ReturnItem()을 추가한다. 그 뒤의 If laptop.IsLoaned Then 블록은 실행되는가. Equipment.TotalCreated 값도 함께 설명한다.

  3. 클래스에 Department라는 문자열 자동 속성을 추가한다. 생성자는 바꾸지 않는다. Main에서 노트북의 담당 부서를 “총무팀”으로 설정하고 출력하는 두 문장을 작성한다.

  4. 아래 코드를 완성 코드의 마지막 출력 뒤에 넣는다고 하자. 객체가 있을 때만 이름을 출력하도록 고친다. 현재 변수 값에서 실제로 어떤 문장이 출력되는지도 설명한다.

    Dim selected As Equipment = Nothing
    Console.WriteLine(selected.Name)

정답과 해설

  1. 이름은 “이름 없음”이다. New Equipment(...)가 생성자를 실행하고, 생성자의 Me.Name = name이 속성의 Set을 실행한다. 공백을 제거한 문자열의 길이가 0이므로 대체 이름을 필드에 저장한다. 출력할 때는 Get이 그 값을 반환한다.

  2. 해당 블록은 실행되지 않는다. 두 변수가 같은 객체를 가리키므로 sameLaptop.ReturnItem()이 노트북의 내부 대여 상태를 False로 바꾼다. 따라서 “노트북 상태: 대여 중” 문장이 출력되지 않는다. 새 객체를 만들지 않았으므로 생성 수는 2다.

  3. 클래스 안에는 다음 선언을 추가한다.

    Public Property Department As String

    노트북을 생성한 뒤 Main에서 다음 두 문장을 실행한다. 설정한 값을 출력하므로 출력 문장은 “담당 부서: 총무팀”이다.

    laptop.Department = "총무팀"
    Console.WriteLine($"담당 부서: {laptop.Department}")

    이번 요구에는 부서 이름을 정리하는 규칙이 없으므로 자동 속성을 선택했다. 나중에 규칙이 필요하면 저장 필드와 Get, Set을 갖춘 속성으로 바꿀 수 있다.

  4. IsNot Nothing으로 객체가 있는 경우를 구별한다.

    Dim selected As Equipment = Nothing
    If selected IsNot Nothing Then
        Console.WriteLine(selected.Name)
    Else
        Console.WriteLine("선택된 비품이 없다.")
    End If

    현재 값은 Nothing이므로 이름을 읽지 않는다. “선택된 비품이 없다.”가 출력된다. 이 확인은 비품 이름이 비었는지를 검사하는 것이 아니라, 이름을 읽을 객체가 존재하는지를 검사한다.

오탈자·오류 제보 비공개로 접수되어 원고 수정에 반영됩니다

이메일 등 개인정보는 받지 않습니다. 답변이 필요한 질문은 아래 댓글을 이용해 주세요.

READER FEEDBACK

질문·의견

내용에 관한 질문이나 더 나은 설명을 위한 의견을 남겨 주세요. 오탈자는 위의 제보 양식이 더 빨리 반영됩니다. 이 댓글은 원래 게시글과 같은 자리에 쌓입니다.

댓글 0

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

댓글을 남기려면 로그인이 필요합니다.