[Unity C#] 클래스 - 2

YongSeok·2022년 7월 12일
0

✏️ 생성자

  • 객체가 생성될 때 자동으로 호출되는 메소드 (new로 메모리를 할당할 때)
  • 생성자는 클래스 이름과 동일하게 정의

👇 생성자 코드 예시

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

public class Player : MonoBehaviour
{
    private string  ID;
    private int     currentHP;

    public Player()
    {
        ID = "김철수";
        currentHP = 1000;
    }
}
// 생성자의 한정자는 public 이며, 반환 형식을 가질 수 없다.
// new 키워드로 메모리를 할당하는 이 때 생성자가 호출된다.

👇 생성자 메소드 오버로딩

// Player Class
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    private string  ID;
    private int     currentHP;

    public Player()
    {
        ID = "김철수";
        currentHP = 1000;
    }
    public Player(string id, int hp)
    {
        ID = id;
        currentHP = hp;
    }
}
// 생성자는 필요에 따라 매개변수를 사용할 수 있다.
// 또한 메소드 오버로딩을 이용해 다양하게 정의해서 활용 가능
// GameController Class
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameController : MonoBehaviour
{
    public Player player01;
    public Player player02;

    private void Awake()
    {
        player01 = new Player();
        player02 = new Player("유니티", 10);
    }
}

✏️ 소멸자

  • 객체가 소면할 때 자동으로 호출되는 메소드 (가비지 컬렉터가 호출을 담당)
  • 소멸자는 "~클래스 이름" 과 같이 정의
private string  ID;
private int     currentHP;

~Player()
{
    // 소멸됩니다
}
// 소멸자의 한정자는 private 이며, 반환 형식과 매개변수를 가질 수 없다.
// 메소드 오버로딩 사용이 불가능 하다.

C#에서 소멸자를 사용하지 않는 이유
C/C++과 다르게 메모리 해제를 직접 하지않고 가비지 컬렉터가 알아서 해주는데 이 가비지 컬렉터 작동 시간을 예측할 수 없다.(쓰레기가 일정 양이 되어야 작동) 명시적으로 소멸자가 구현되어 있으면 가비지 컬렉터가 object로 부터 상속 받은 Finalize()메소드를 클래스의 족보를 타고 올라가며 호출(성능저하) 가비지 컬렉터가 프로그래머보다 똑똑하게 객체 소멸을 처리해서 굳이 사용하지 않는다.


✏️ 얕은복사, 깊은복사

👇 얕은복사 예시코드

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

public class Test : MonoBehaviour
{
    private Player player01;
    private Player player02;

    private void Awake()
    {
        player01 = new Player("김철수", 1000);
        player02 = player01;
        player02.ID = "유니티";

        Debug.Log($"ID : {player01.ID}");
        Debug.Log($"ID : {player02.ID}");
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    public string ID;
    private int currentHP;

    public Player(string id,int hp)
    {
        ID = id;
        currentHP = hp;
    }
}

두명의 플레이어 정보를 다루기 위해 player01과 player02 객체 인스턴스를 선언, player02는 player01에 설정한 데이터와 동일하게 적용하고, ID만 바꾸고 싶다. 아래 코드와 같이 player02 = player01; 과 같이 적용하면 player02.ID 의 값이 바뀔까❓❓ 정답은 NO❗ 왜냐하면 얕은 복사를 했기 때문이다

  • 값을저장하는 int, float은 값을 복제하는 것이기 때문에 int a = b 와같이 적용하면 b에 저장된 값이 a에 적용 되지만 클래스 변수의 경우 player02 = player01과 같이 적용하면 player01의 실제 데이터가 저장되어 있는 힙영역의 주소가 player02에 저장된다
  • player01과 player02는 같은 메모리를 참조하고 사용하게 된다

👇 깊은복사 예시코드

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

public class Player : MonoBehaviour
{
    public string ID;
    private int currentHP;

    public Player()
    {
        ID = "고박사";
        currentHP = 1000;
    }

    public Player (string iD, int currentHP)
    {
        ID = iD;
        this.currentHP = currentHP;
    }

    public Player DeepCopy()
    {
        Player clone    = new Player();
        clone.ID        = ID;
        clone.currentHP = currentHP;
        return clone;
    }
}
// private Player player01; 은 스택 영역에 클래스 변수를 생성하는 행위
// player01 = new Player(); 는 힙 영역에 메모리를 할당 받는 행위
// 즉, 메모리 생성을 위해 DeepCopy() 메소드를 만들어 내부에서 new로 메모리를 생성
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour
{
    private Player player01;
    private Player player02;

    private void Awake()
    {
        player01 = new Player("고박사", 1000);

        player02 = player01.DeepCopy();
        player02.ID = "유니티";

        Debug.Log($"ID : {player01.ID}");
        Debug.Log($"ID : {player02.ID}");
    }
}
  • DeepCopy 메소드가 호출되면 Player타입의 변수 clone을 선언하고 메모리를 할당한후 현재 Player클래스에 설정되어있는 모든 변수의 값을 그대로 저장하고 설정이 완료된 Player타입의 clone변수를 반환

  • 결과 : Player01의 메모리 공간이아닌 clone에 의해 생성된 새로운 메모리 공간을 player02가 사용하기에 값을 바꿀 수 있다

✏️ this

  • 클래스의 변수나 메소드에 접근할 때는 대상이 필요
  • 클래스 내부에서 자기 자신의 변수나 메소드에 접근할 때 this 사용
  • 변수 이름, 메소드 이름만 사용할 경우 default로 this가 자동 지정

👇 코드 예시

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

public class Player : MonoBehaviour
{
    public string ID = "김철수";

    public void SetID(string ID)
    {
        Debug.Log($"ID : {ID}");
        Debug.Log($"ID : {this.ID}");
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameController : MonoBehaviour
{
    public Player player01;
    
    private void Awake()
    {
        player01 = new Player();
        player01.SetID("유니티");
    }
}

Tip. 위의 코드와 같이 클래스 멤버 변수와 메소드 내부의 지역변수 이름이 같을 경우 ID와 같이 이름만 사용하면 지역 변수를 지칭하게 된다. 이럴때 this.ID와 같이 클래스 멤버 변수를 지칭하도록 사용한다.

0개의 댓글