본문 바로가기

C#/기본 문법

C# 객체 지향 시작 및 복사와 값 참조


1) 절차(Procedure)지향 : 함수(메소드)로 구현
-  장점 : 굉장히 심플함
-  단점 : 함수의 실행순서에 종속적어서 유지보수 힘듬, 프로그램이 거대해질수록 유지보수 힘들고 로직이 꼬일수 있음

2) 객체(OOP : Object Oriented Programming)지향 : 모든것을 객체로 생각함
- 속성, 기능 구성
-  ex) Knight
-  속성 : hp, attack, pos
-  기능 : Move, Attack, Die

 

3) 클래스와 구조체의 차이
- 클래스 : 기본적으로 참조(Ref)를 해서 넘김
- 구조체 : 기본적으로 복사(Copy)를 해서 넘김(정적할당, 동적할당시에도 복사로 적용됨)

 

4) 얕은복사(Shallow Copy)와 깊은복사(Deep Copy)

- 얕은복사 : 참조를 복사

클래스는 참조 형식이다. 그렇기 때문에 다음과 같이 복사를 해주면 문제가 발생한다.

class Monster
{
     public int hp;
     public int damage;
     
     public Monster(int hp, int damage)
     {
         this.hp = hp;
         this.damage = damage;
     }
}
Monster myMonster = new Monster(100, 5);

Monster otherMonster = myMonster;          // 얕은 복사
otherMonster.hp = 200;

Console.WriteLine($"myMonster HP : {myMonster.hp}");
Console.WriteLine($"otherMonster HP : {otherMonster.hp}");

 

두 참조 변수는 같은 객체를 가리킨다.

 

객체는 하나만 생성하고 그걸 가리키는 참조 변수는 두 개(myMonster, otherMonster)가 된 것이다. 그러니, otherMonster의 체력을 변경해도 myMonster의 체력이 같이 변경되는 일이 벌어졌다.

 

즉, 제대로된 복사를 해주려면 새로운 객체를 생성해고 내부 값들을 복사하여 넘겨주는 깊은 복사 작업이 필요하다.

 

 

- 깊은복사 : 데이터 값 전체를 복사

C#에서는 깊은 복사를 자동으로 해주는 구문이 없기 때문에 직접 만들어 줘야 한다.

class Monster
{
     public int hp;
     public int damage;
     
     public Monster(int hp, int damage)
     {
         this.hp = hp;
         this.damage = damage;
     }
     
     public Monster DeepCopy()       // 깊은 복사 메소드 생성
     {
         Monster newMonster = new Monster(0, 0);
         newMonster.hp = this.hp;
         newMonster.damage = this.damage;
         
         return newMonster;
     }
}
Monster myMonster = new Monster(100, 5);

Monster otherMonster = myMonster.DeepCopy();   // 깊은 복사
otherMonster.hp = 200;

Console.WriteLine($"myMonster HP : {myMonster.hp}");
Console.WriteLine($"otherMonster HP : {otherMonster.hp}");

서로 다른 객체를 가리킨다.

 

새로운 객체를 만들어서 내부값들을 복사해주고 리턴하는 DeepCopy() 라는 메소드를 만들었다. 이제 myMonster otherMonster는 서로 다른 객체를 참조하고 있다.

 

- 참고 : ICloneable 인터페이스를 활용하여 깊은 복사를 만들 수도 있다

 


 

 

 

학습본문


using System;
using System.Numerics;

namespace Rookiss_CSharp
{
    class Program
    {
        class Knight
        {
            // 기본적으로 접근지정자는 internal로 됨(에셈블리 내에서만 접근됨)
            // int hp;
            // internal int hp;
            
            public int hp;
            public int attack;

            /// <summary>
            /// 깊은복사
            /// 새롭게 동적할당 + 값 복사후 resturn
            /// </summary>
            /// <returns></returns>
            public Knight Clone()
            {
                Knight knight = new Knight();
                knight.hp = this.hp;
                knight.attack = this.attack;
                return knight;
            }

            public void Move()
            {
                Console.WriteLine("Knight Move");
            }

            public void Attack()
            {
                Console.WriteLine("Knight Attack");
            }
        }

        struct Mage
        {
            public int hp;
            public int attack;
        }

        static void KillMage(Mage mage)
        {
            mage.hp = 0;
        }

        static void KillKnight(Knight knight)
        {
            knight.hp = 0;
        }

        static void Main(string[] args)
        {
            // Mage mage;
            Mage mage = new Mage();
            mage.hp = 100;
            mage.attack = 50;
            KillMage(mage); // 구조체라서 값 복사로 넘어감(원본 수정필요시 ref 필요) => Mage mage;, Mage mage = new Mage();로 해도 동일

            Mage mage2 = mage; // 복사라서 mage의 hp 그대로고, mage2의 hp: 10이됨(mage와, mage2는 별도라고 생각하면 됨)
            mage2.hp = 10;

            Knight knight = new Knight();
            knight.hp = 100;
            knight.attack = 10;
            KillKnight(knight); // 클래스라서 기본적으로 참조로 넘어감(ref 명시 안해줘도, ref로 연산함)

            Knight knight2 = knight; // 참조라서 knight의 hp: 10이됨(참조라서 knight2와 knight가 동일시됨)
            knight2.hp = 10;

            Knight knight3 = knight.Clone(); // 깊은복사
        }
    }
}

 

 

 

참조

https://www.inflearn.com/courses/lecture?courseId=324718&roadmapId=355&tab=curriculum&type=LECTURE&unitId=32806&subtitleLanguage=ko

 

복사(값)와 참조 | [C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part1: C# 기초 프로그래밍 입문

복사(값)와 참조

www.inflearn.com

35강 객체지향의 시작 ~ 36강 복사(값)와 참조

 

 

얕은복사와 깊은복사

https://daekyoulibrary.tistory.com/entry/C-%EC%96%95%EC%9D%80-%EB%B3%B5%EC%82%ACShallow-Copy%EC%99%80-%EA%B9%8A%EC%9D%80-%EB%B3%B5%EC%82%ACDeep-Copy-ICloneable-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4

 

[C#] 얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy) + ICloneable 인터페이스

*이 글은 책을 바탕으로 공부한 글입니다. C#의 클래스 부분을 공부하고 있었다. 어떤 객체지향언어를 배우든 클래스와 생성자란 개념이 나왔고, 이것은 익숙하게 알고 있는 내용이었다. 이번에

daekyoulibrary.tistory.com

 

'C# > 기본 문법' 카테고리의 다른 글

C# 생성자  (0) 2025.11.01
C# 메모리 영역  (0) 2025.11.01
C# TextRPG  (0) 2025.11.01
C# 간단한 연습문제  (0) 2025.10.27
C# 기초 문법 정리 - 함수  (0) 2025.10.27