유니티/C++개발자의 C#입문

C++개발자의 C#입문(1) - C#과 C++은 뭐가 다를까?

강목근 2024. 5. 28. 21:32

본 포스트는 철저히 C++만 써본 개발자가 C#을 입문하면서 공부한 내용 + 느낀 내용에 대해서 다루므로, 객관성이 보장되지 않습니다.

 

저는 대학 시절 C++로만 개발을 진행했고, C#의 경우는 진지하게 사용해본 경험이 없습니다.

유니티는 설치되어 있었지만, 에셋스토어의 에셋을 추출하여 다른 프로젝트에 사용하기 위해 설치한 것이라 개발을 한 경험은 없습니다.

 

졸업 이후 취업을 준비하면서, 유니티 개발자 구인 공고가 많은 것을 알게되어 C#을 공부해보기로 했습니다.

 

절차지향 프로그래밍

  • 프로그램을 일련의 절차로 구성하는 방식
  • 데이터와 기능이 분리되어 있어 데이터를 직접 조작하는 방식
  • 코드의 재사용성이 낮고, 프로그램 구조가 복잡해지면 관리가 어려워진다.
int add(int a, int b) {
    return a + b;
}

int main() {
    int num1 = 10, num2 = 20;
    int result = add(num1, num2);
    std::cout << "Result: " << result << std::endl;
    return 0;
}
  • 우리가 코딩테스트 문제를 푸는 것과 비슷하게, 특정한 하나의 목표가 명확하여 해당 기능에 대한 로직을 함수로 나누어 main 함수를 통해 그 목표를 달성할 수 있을 때 자주 사용한다. (TOP -> DOWN)
  • 또한 코드의 이해가 비교적 쉽다. 

 

객체지향 프로그래밍

  • 프로그램을 객체라는 독립적인 단위로 구성하는 방식
  • 데이터와 기능이 하나의 객체에 "캡슐화"되어있다.
  • 객체 간 상호작용을 통해 프로그램이 동작하며, 코드 재사용성이 높다.
  • 프로그램 구조가 복잡해져도 객체 단위로 관리할 수 있어 유지보수에 좋다.
  • 구조를 설계하는 것이 어렵다.
class Calculator {
private:
    int num1, num2;

public:
    void setNumbers(int a, int b) {
        num1 = a;
        num2 = b;
    }

    int add() {
        return num1 + num2;
    }
};

int main() {
    Calculator calc;
    calc.setNumbers(10, 20);
    int result = calc.add();
    std::cout << "Result: " << result << std::endl;
    return 0;
}
  • 위의 절차지향 예시로 나타낸 코드를 객체지향으로 수정한 것이다.
  • 이는 단순한 예시용 코드로, 절대 좋은 코드는 아니다.
  • 데이터(num1, num2)와 기능(setNumbers, add)가 하나의 객체에 캡슐화되어있다.

 

절차지향과 객체지향을 설명한 이유는, 위 내용을 이해해야 C#과 C++의 차이를 좀 더 명확하게 알 수 있기 때문이다.

 

C++과 C#의 공통점

C++은 "멀티 패러다임"언어이다. C언어에서 발전하여 개발된 언어이므로 절차지향과 객체지향의 특징을 모두 지니고 있다.

 

C#은 객체지향 언어이다. C++을 기반으로 만들어져서 그런지 처음 접했을 때도 문법과 코드가 어색하지 않았다.

 

둘의 공통점은 객체지향 언어의 특징들이라 볼 수 있다. 객체지향의 네가지 특징이 있는데,

  • 추상화
  • 상속
  • 다형성
  • 캡슐화

가 있다. 위 내용은 다른 포스트에서 따로 상세하게 다룰 예정이다.

위 공통점으로 인해 첫 유니티 게임 개발에 금방 적응하여 프로젝트를 성공적으로 마무리 할 수 있었는데, 해당 내용 또한 가능하다면 추후에 다루도록 하겠다.

 

C++과 C#의 차이점?

이제 본문이다. 두 언어의 차이점이 무엇인지 서술한다.

 

1. 메모리 관리

C++
원시 포인터를 자유롭게 사용해 메모리 주소에 직접 접근하고, 조작하는 것이 가능하다.
본래 new와 delete를 이용하여 직접 메모리를 관리해야 했으나, C++11에 추가된 스마트 포인터를 사용하여 자동으로 메모리 관리를 할 수 있게 되었다.
shared_ptr에 의해 순환참조로 메모리 누수가 발생할 수 있다. (weak_ptr로 어느정도 해결됨)

 

C#
더 이상 사용하지 않는 객체를 메모리에서 자동으로 해제하는 가비지 콜렉터를 사용한다.
가비지 콜렉터가 메모리 이외의 시스템 리소스를 보유하고 있는 객체의 메모리 해제를 어렵게 만들어 리소스 누수가 발생할 수 있다고 한다. (이 문제를 실제로 겪은 적은 없다.)
이 가비지 콜렉터는 CLR을 통해 지원된다고 하는데, 이에 대해서 추후에 공부하여 포스트하겠다.
포인터를 사용한 메모리 주소에 대한 직접적인 접근이 제한된다. C#에서는 이 행위를 안전하지 않다고 판단한다.

 

2. C++은 멀티 패러다임, C#은 객체지향

C++
객체지향과 절차지향의 특징을 모두 갖고 있어 구현에 있어서 자유롭다.
namespace Vector3
{
	inline XMFLOAT3 XMVectorToFloat3(XMVECTOR& xmvVector)
	{
		XMFLOAT3 xmf3Result;
		XMStoreFloat3(&xmf3Result, xmvVector);
		return(xmf3Result);
	}
	/*
    그 외 많은 코드들...
    */
}​

실제로 진행했던 프로젝트의 코드 일부이다. 전체 코드가 공유하는 하나의 헤더 파일에 위와 같이 함수를 선언하여 사용할 수 있게 하였는데, 위 코드는 객체지향적 코드가 아닌 절차지향적 코드에 가깝다.
이와 같이 두 특징을 모두 지닌 멀티 패러다임 언어이므로, 개발에 있어서 C#에 비해 자유롭다고 느꼈다.

 

C#
온전히 객체지향적 언어이다.
모든 것을 객체로 취급한다.
실제로 스크립트를 생성하면 해당 스크립트와 동일한 이름의 클래스로 코드가 기본적으로 작성되어 있다.
컴포넌트 구조로, 각각의 독립된 모듈로 작동한다.

 

물론 더 많은 차이점이 존재하겠지만, 실제로 사용하면서 '아, 이런 게 다르구나'하고 느낀 것들은 위의 내용이다.

위의 차이점 때문인지는 모르겠으나, C#을 사용하면서 C++을 사용할 때보다 싱글톤 패턴을 자주 사용했다. 

유튜브와 구글에 널려있는 한국어 유니티 강좌에 보면, 대부분 GameManager를 통해 게임 개발을 진행한다.

 

싱글톤을 사용해서 개발이 굉장히 편하고, 속도가 빨라지긴 했으나 이후에 싱글톤 클래스를 수정할 경우 이를 참조하는 모든 클래스에서 수정이 이루어져야 하기에 유지보수에 좋지 않다고 생각해 아예 사용하지 않고 게임을 하나 만들어볼까 한다.

 

그래서 결론이 뭔데?

  • C#이 C++과 다른 점이 많긴 하지만, 객체지향 언어이기 때문에 C++ 개발을 하던 개발자가 C#에 적응하는 것이 크게 어렵지 않았다.
  • 코루틴과 같은 기능을 C++에서 사용하려고 할 땐 사용자가 정의해야 하는 부분이 너무 많아 어려웠던 반면, C#에서 사용할 때는 간편하게 원하는 기능을 구현할 수 있었다.
  • 특히나 유니티에서 에디터를 제공하고, 해당 에디터를 통해 class로 작성한 각 모듈(컴포넌트)를 게임 오브젝트에 손쉽게 추가하여 개발이 가능한 것 때문에 개발의 난이도가 확 낮아졌다 생각한다.
  • 가장 좋다고 느낀 부분은 사실 "한국어 강의"가 굉장히 많다는 것이다. 기존 C++로 DirectX 12를 개발하거나 할 때는 한국어 정보나 강의가 좀 부족해서 영어로 된 글을 많이 읽었는데, 이번에 C#으로 게임을 개발하면서 넘치는 한국어 강의를 접할 수 있었다.
  • 아직 시작한지 일주일도 되지 않았기에, 위 느낀점들이 나중에 바뀔 수도 있다. 가능하다면 공부하면서 느끼는 것들을 꾸준히 포스팅하려고 한다.