본문 바로가기

Unity/▶ Unity Composition

[Unity Composition]#4. 참조 타입

728x90
반응형

참조 타입

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Zoo : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Animal tom = new Animal();
        tom.name = "톰";
        tom.sound = "냐옹";

        tom.Playsound();
    }

  
}

위의 코드를 살펴보면, Animal 타입의 변수 tom에 값을 할당할 때에는 new키워드를 사용하여 새로운 Animal 오브젝트를 생성하고 값을 할당하는 것을 볼 수 있다.

 

이때 Animal 타입은 int, char과 같은 형식의 변수들은 바로 값을 할당하는 것과 차이를 보이는데 이는 클래스로 만든 변수참조 타입이기 때문이다.

클래스로 만든 변수는 실체화된 오브젝트가 아니므로
new를 이용하여 오브젝트를 개별적으로 생성해야한다.

Animal 오브젝트 두 개 생성하기(1)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Zoo : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Animal tom = new Animal();
        tom.name = "톰";
        tom.sound = "냐옹";

        Animal jerry = new Animal();
        jerry.name = "제리";
        jerry.sound = "찍찍";

        tom.Playsound();
        jerry.Playsound();
    }

}

Animal 오브젝트 두 개 생성하기(2) : 참조값 변경

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Zoo : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Animal tom = new Animal();
        tom.name = "톰";
        tom.sound = "냐옹";

        Animal jerry = new Animal();
        jerry.name = "제리";
        jerry.sound = "찍찍";
		
        jerry = tom;
        jerry.name = "미키마우스";
        
        tom.Playsound();
        jerry.Playsound();
    }

}

해당 코드를 직관적으로 이해하면 jerry에 tom에 저장된 값가 각각의 변수에 맞게 저장된 후 jerry의 이름이 변경됐다고 생각할 수 있다.

하지만 실제 출력해보면,

미키: 냐옹
미키: 냐옹

으로 나오게 된다.

 

이는 jerry = tom;라는 코드가 우리가 생각하는 로직과 다르기 때문에 발생하는 오류이다.

 

클래스의 변수는 오브젝트 자체가 아닌 오브젝트를 가리키는 참조값을 저장한다.
참조값: 실제 오브젝트의 메모리 주소에 대응되는 값. 메모리 주소 값 자체는 아니며 C# 프로그램 구동 시 메모리 주서와 대응되는 값.

 

클래스의 변수에 할당된 참조값의 위치에는 '진짜' 오브젝트가 존재한다. 클래스의 변수의 값이 변경된 경우 해당 변수에 저장된 참조값을 통해 실제 오브젝트를 찾아가 해당 오브젝트의 변수를 수정하는 방식으로 변경이 이루어진다.

 

다시 말해, jerry에 할당된 참조값을 tom에 할당한 참조값을 덮어쓰기 하는 것으로 tom과 jerry가 같은 오브젝트를 가리키게 되는 것이다.

 

결론적으로 변수는 두 개 존재하지만 두 변수가 참조값을 통해 가리키는 Animal 오브젝트는 하나이므로, 둘 중 하나의 오브젝트를 수정하는 것은 두 오브젝트를 동시에 수정하는 것과 같은 결과를 나타낸다.

 

이때 jerry 오브젝트는 참조값이 끊겼기 때문에 사용할 수 없는 오브젝트가 된다. 이렇게 사용할 수 없는 오브젝트는 C#의 가비지 컬렉터가 자동으로 삭제하여 정리한다.

 

이는 C언어의 구조체 포인터와 비슷하다.

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct A{
    int data;
    char name;
}AA;

int main(void){
   struct A *stra = &AA;
   struct A *strb ;

   stra->name = 'A';
   stra->data = 1;

   strb = stra;

   strb->data = 10;
   printf(">%d",stra->data);


}

구조체를 정의하고 해당 구조체를 위치로 하는 구조체 포인터 두 개를 선언한 후 하나의 구조체 포인터에 구조체를 할당하고 값을 초기화한다.  이후 초기화한 구조체를 초기화하지 않은 구조체에 대입(위치를 같게)하면 클래스의 변수를 할당하는 위의 코드와 같은 양상을 볼 수 있다.

 

하나의 실체와 여러 개의 참조 변수

C# 에서 클래스 타입의 변수는 참조 타입으로 동작한다.

참조 타입은 실체는 하나지만 이 실체를 부르는 형태를 여러 개로 만들 수 있다. (이것도 C언어에서 구조체를 정의하고 여러 개의 선언이 가능한 것과 같은 맥락이다.)

 

이런 참조 타입이 중요한 이유는 컴포넌트의 참조를 변수로 가져와서 사용하는 것이 가능하기 때문이다.

 

컴포넌트의 참조를 변수로 가져와서 사용하는 것이 가능하다!

 

기본(값) 타입 C# 내장 변수(int,string 등)
해당 변수 공간에 값 자체를 저장

값 타입에 값을 할당하면 값의 참조가 아닌 값의 사본이 할당된다.
참조 타입 실체(값)으로 향하는 참조를 저장

출처:&amp;amp;nbsp;https://kingpodo.tistory.com/54

 

변수의 타입을 사용하는 타입을 기준으로 분류하면 다음과 같다.

기본(값) 타입 참조 타입
Class 타입
유니티의 모든 컨포넌트
C# 스크립트
C# 내장 변수
- bool
- int
- float
- char
....

struct 타입(구조체)
- Vector3
- color

class로 만든 대부분의 타입은 참조로 동작하며, 유니티의 오브젝트와 컴포넌트 등이 클래스로 지정되어 있다. 따라서 구조체 타입을 제외하면 대부분의 변수는 참조 타입으로 동작한다.

 

 

정리

  • 클래스는 오브젝트를 생성하는 툴이다.
  • new를 사용하여 클래스로부터 오브젝트를 생성한다.
  • 한 클래스로부터 여러 오브젝트를 만들 수 있다.

 

728x90
반응형
댓글