앞으로 공적으로는 C++ 을 쓰고, 사적으로는 C# 으로 쓰기로 마음먹었다.

C# 자체도 좋은 언어이지만, WCF, WPF, Silverlight, ASP.Net 사용도 고려해 볼때 꼭 익혀놓아야 하는 언어임은 틀림없다.

C# 을 쓰면서 느끼는 C++ 과의 차이점들을 정리해 놓고자 한다.

1. Windows Application 개발 환경의 차이.

C# 의 개발 환경은 전통적인 Visual C++ 보다는 Visual Basic 에 가깝다. 폼을 디자인하고, 이 폼을 동작하는 코드를 별도로 코딩하는 환경은 보다 RAD 를 지향하고 개발생산성을 중시한 C# 의 철학을 잘 보여준다.
또한 윈도우즈 어플 개발시 Visual C++ 에서 나눠져 있던 SDI, MDI, Dialog Based 구분이 없어지고 C# 에서는 Windows Forms 이라는 하나의 형태로만 존재한다. ( 도구상자에 MDI Parent 라는 컨트롤이 존재하는 것은 확인했다. )

2. 보다 강력해진 Intellisense 
Visual C# 의 Intellisense 는 정말 강력하다.
예약어로 정의된 키워드들과, 라이브러리에 이미 정의된 멤버들이 팝업으로 표시되는 것은 물론이고, 심지어 개발자가 정의한 변수/함수 들도 인텔리센스에서 나타난다. 이걸 처음에 보고 얼마나 감동받았는지 ㅜ.ㅜ
덕분에 코딩 시간이 많이 단축된다.
여담이지만, TopCoder 를 할 때 C++ 개발자들은 조금이라도 코딩을 빨리 하기 위해서 자주 사용하는 긴 문장들은 매크로를 즐겨 쓴다.

예 )
#define FOR(i,a,b) for(int i = (a); i < (b); ++i)
#define REP(i,n) FOR(i,0,n)

그런데 C# 에서는 굳이 저릴 필요가 없다. 인텔리센스가 잘 받쳐주고 있으니까...
사실, 인텔리센스는 언어의 기능이 아니라 툴의 기능이므로, 이런 강력한 인텔리 센스는 Visual C++ 에도 충분히 도입할 수 있다고 보여지는데... C# 과 C++ 에 차이를 둔 것은 결국 정책적으로 MS 가 C# 을 밀고 있다는 이야기만 확인시켜주는 셈이다...
그리고 여담. 나는 ret 이란 변수를 즐겨 쓰는데 이걸 쓰다보면 인텔리센스가 return 으로 자꾸 인식해서 좀 불편하다.


3. C# 은 더욱 더 강력하게 객체지향적이다.

자료구조등을 새로 선언할때 class 형으로 만들어서 써야 한다. 자바랑 비슷하다.
자료구조나 컨트롤들 하나 하나가 모두 철저하게 객체로 관리하고, 객체지향적으로 코딩해야 한다는 느낌이 팍팍 한다. 간혹보면 C++ 을 C 처럼 쓰는 것 처럼 구조적 프로그래밍 방식으로 코딩하는건 C# 에서는 거의 불가능해졌다.  


4. 자료 구조의 차이

C++ STL 의 List, Vector 대신에 C# 에서는 ArrayList 가 제공된다.
C++ STL 의 Map 대신에 C# 에서는 Hashtable, Dictionary 가 제공된다.
C++ STL 의 Pair 대신에 C# 에서는 KeyValuePair 가 제공된다.
C++ 의 경우 STL 에서 제공하는 자료구조들을 쓰기 위해서 C# 에서는 Collection 을 인클루드 한다.


5. 형변환이 보다 엄격하면서도, 쉬워졌다.

예를 들어 C++ 에서 허용되는 다음과 같은 코드가 C# 에서는 에러가 난다.



반면에 데이터 타입의 변환은 Convert 라는 객체를 통해서 ToString, ToInt16, ToInt32, ToDateTime 과 같이 다양한 형태의 형변환을 메소드로 지원해서 형변환이 아주 쉬워진다.

6. 클래스 멤버들의 public, private, protected 구분이 더 엄격해졌다.

C++ 과 달리 C# 에서는 메소드, 변수 마다 붙인다.



struct 의 경우 C++ 에서는 별도로 선언을 하지 않아도 암시적으로 모든 멤버가 public 으로 선언된다. 하지만 C# 에서는 struct 를 사용할때 위와 같이 멤버들에 대해서 명시적으로 public 인지 지정해야 한다.

7. C# 은 가비지 콜렉션을 지원하며 C++ 과 달리 new 는 존재하지만 delete 는 없다.

C# 에서 객체를 생성할때는 항상 new 로 생성한다. 하지만 C++ 과 달리 delete 를 해줘야 하는 것이 아니라, 가비지 콜렉터가 자동으로 매니지드 힙의 메모리 영역에서 생성된 객체의 메모리를 지워준다.

예를 들어 C# 에서 배열을 선언할 때 아래와 같이 쓴다.
int [] dat = new int [];

2차원 배열은 아래와 같이 할당한다.
int [,] dat = new int [100,100];  // 다중 배열에서 콤마를 쓰는 이런 방식이 처음엔 상당히 생소했다.

new 로 생성하지만 delete 를 하지는 않는다.
명시적으로 프로그래머가 힙 영역에서 데이터를 삭제할 때는 Dispose 명령을 사용한다.  


댓글을 달아주세요!
  1. Neon 2009.11.10 16:39 신고  댓글주소  수정/삭제  댓글쓰기

    3.은 좀 태클 걸어야겠군요. struct 형도 쓸 수 있고 그 작동이 class와 약간 다릅니다. class의 경우 pointer 같은 느낌이고, struct의 경우 C의 struct를 연상한달까요? operator= 같은 연산자에서도 작동이 달라서, class의 경우에는 pointer 연산하듯 처리가 되고, struct의 경우에는 내용이 똑같은 새로운 struct를 만드는 처리가 됩니다.

  2. BlogIcon hyperdash 2009.11.13 00:15 신고  댓글주소  수정/삭제  댓글쓰기

    그래도 난 C++.....

  3. 김훈동 2009.11.13 17:57 신고  댓글주소  수정/삭제  댓글쓰기

    2. 에 추가하여... 코드 스니펫 이라는 게 있는데.... 자주 쓰는 긴 코드의 코딩 패턴을 XML 로 정의 해놓고, 거기에 바뀌는 부분만을 tab 으로 옮겨가며 코딩 하는게 있어...
    예를 들어 prop 라고 치고 tab 을 두번 눌러봐바.... 자바에서 멤버변수 선언하고 getter , setter 를 쫙 써준 다음에 그걸 하나의 DTO 클래스 혹은 ValueObjce 클래스로 만들어서 객체를 쓰던 방식을 .NET 에서는 프로퍼티 라는 걸로 깔끔하게 선언해 쓰는 것을 권장하고 있는데... prop 텝 2번 눌러서 멤버변수 영역에서 변수를 프로퍼티 로 정의하면 private 변수와 이를 public 으로 노출하는 getter 와 setter 가 한방에
    코드 제너레이션이 가능해...
    swich 구문이나 foreach 구문 등도 미리 예약된 코드 스니펫 단축명령어가 다 존재하고 혹은 내가 자주 사용하는 코딩 패턴을 코드 스니펫으로 custom 지정도 가능해.... 그리고 custom 코드 스니펫 만들때는 복잡하게 XML 을 일일이 짜줄 필요는 없고.... 코드 스니펫을 자동으로 만들어서 VS 에 연동시켜주는 Free 소프트웨어들이 인터넷에 많이 돌아다녀... 자주쓰는 DB 접속 구문이나 Try Catch 구문, Using 구문, 그리고 특히 프로젝트 표준 주석등을 쓸때 스니펫을 쓰면 딱이쥐...

  4. 김훈동 2009.11.13 18:07 신고  댓글주소  수정/삭제  댓글쓰기

    4. 에 추가하여... .NET Generic 도 잘 배워봐...
    STL 의 대부분의 기능이 구현되어 있고.. Java Generic 보다 훨씬 빠로고 안정적이야..

    아래는 C++ 템플릿과 C# Generic 의 차이를 알려주는 MSDN 의 내용....

    [generics 구현]

    C++에서 템플릿은 사실 매크로일 뿐이며 컴파일된 이진수로 유지되지 않습니다. 특정 형식의 템플릿 클래스를 사용하지 않으면 컴파일러가 템플릿 코드를 컴파일할 수도 없습니다. 형식을 지정하면 컴파일러가 코드를 인라인에 삽입하여 generic 형식 매개 변수의 모든 항목을 지정된 형식으로 바꿉니다. 템플릿 클래스에서 발생한 컴파일 오류는 템플릿 클래스를 사용할 때만 발견할 수 있습니다. 또한 특정 형식을 사용할 때마다 컴파일러는 사용자가 이미 응용 프로그램의 다른 곳에서 템플릿 클래스에 대해 해당 형식을 지정했는지에 관계없이 형식별 코드를 삽입합니다. 따라서 코드가 비대해져 로드 시간이 길어질 뿐 아니라 메모리 공간도 많이 차지하게 됩니다.

    .NET 2.0에서는 generics가 IL(Intermediate Language) 및 CLR 자체를 기본적으로 지원합니다. generic C# 서버 쪽 코드를 컴파일하면 컴파일러가 이를 다른 모든 형식과 마찬가지로 IL로 컴파일합니다. 그러나 IL에는 실제 특정 형식의 매개 변수나 자리 표시자만 들어 있습니다. 또한 generic 서버의 메타데이터에는 generic 정보가 들어 있습니다.

    클라이언트 쪽 컴파일러는 해당 generic 메타데이터를 사용하여 형식의 안전성을 지원합니다. 클라이언트가 generic 형식 매개 변수 대신 특정 형식을 제공하는 경우 클라이언트의 컴파일러는 서버 메타데이터에 있는 generic 형식 매개 변수를 지정된 형식으로 대체합니다. 그러면 generics가 전혀 사용되지 않은 것처럼 클라이언트의 컴파일러에 서버의 형식별 정의가 제공됩니다. 이러한 방법으로 클라이언트 컴파일러는 올바른 메서드 매개 변수, 형식 안전성 검사 및 형식별 IntelliSense®도 적용할 수 있습니다.

    흥미로운 점은 .NET이 서버의 generic IL을 기계어 코드로 컴파일하는 방식입니다. 사실, 실제로 만들어지는 기계어 코드는 지정된 형식이 값 형식인지 아니면 참조 형식인지에 따라 달라집니다. 클라이언트가 값 형식을 지정하면 JIT 컴파일러가 IL에 있는 generic 형식 매개 변수를 특정 값 형식으로 바꾸고 네이티브 코드로 컴파일합니다. 그러나 JIT 컴파일러는 이미 생성한 형식별 서버 코드를 추적합니다. 이미 기계어 코드로 컴파일한 값 형식을 사용하여 generic 서버를 컴파일하도록 JIT 컴파일러에 지정하는 경우 해당 서버 코드에 대한 참조만 반환됩니다. JIT 컴파일러는 차후의 모든 항목에서 동일한 값 형식별 서버 코드를 사용하므로 코드가 비대해지지 않습니다.

    클라이언트가 참조 형식을 지정하면 JIT 컴파일러가 서버 IL에 있는 generic 매개 변수를 개체로 바꾸고 네이티브 코드로 컴파일합니다. 해당 코드는 차후의 모든 참조 형식 요청에서 generic 형식 매개 변수 대신 사용됩니다. 이러한 방법으로 JIT 컴파일러는 실제 코드만 다시 사용합니다. 인스턴스는 여전히 크기에 따라 관리 힙에 할당되며 캐스팅은 없습니다.

    [generics 이점]

    .NET에서는 generics를 구현할 때 사용한 코드와 작업을 generics를 사용할 때 다시 사용할 수 있습니다. 값 형식을 사용하거나 참조 형식을 사용하거나에 관계없이 코드를 비대하게 만들지 않고도 형식 및 내부 데이터를 변경할 수 있습니다. 코드를 한 번 개발하고 테스트하고 배포한 후에는 모든 컴파일러 지원과 형식 안전성이 보장되는 상태에서 미래의 형식을 포함한 모든 형식에 다시 사용할 수 있습니다. generic 코드를 사용하면 값 형식을 boxing 및 unboxing하거나 참조 형식을 다운 캐스팅하지 않아도 되므로 성능이 크게 향상됩니다. 값 형식을 사용하면 형식에 액세스할 때 일반적으로 성능이 200% 향상되며, 참조 형식을 사용하면 100%의 성능 향상을 기대할 수 있습니다. 물론 전체 응용 프로그램의 성능은 향상될 수도 있고 그렇지 않을 수도 있습니다. 이 기사에서 사용한 소스 코드에는 간단한 루프에서 스택을 실행하는 마이크로 벤치마크 응용 프로그램이 포함되어 있습니다. 이 응용 프로그램을 사용하면 개체 기반 스택과 generic 스택에서 값 형식 및 참조 형식을 사용해 볼 수 있으며 루프 반복의 수를 변경하여 generics가 성능에 미치는 영향을 확인할 수도 있습니다.

  5. 김훈동 2009.11.13 18:13 신고  댓글주소  수정/삭제  댓글쓰기

    7. 에 추가하여...
    .NET 은 기본적으로 명시적인 delete 는 없는데....
    프로젝트를 하다보면 그시점에 명시적으로 delete 를 하고싶을때가 분명 있거든... 그때 쓰는게... using 구문이쥐...
    네임스페이스 지정하는 using 문 말고... 아래 같은거 할때 쓰는 using...
    파일오픈 객체 소멸을 가비지 컬렉터한테 넘기는 우는 처음 시작하는 .NET 개발자가 자주 범 하는 실수 중 하나쥐...

    using (System.IO.StreamReader sr = new System.IO.StreamReader(@"C:\Users\Public\Documents\test.txt";))
    {
    string s = null;
    while((s = sr.ReadLine()) != null)
    {
    Console.WriteLine(s);
    }
    }

  6. BlogIcon mynotepad 2009.11.16 01:32 신고  댓글주소  수정/삭제  댓글쓰기

    오호... Neon 님, 훈동군 ㄳㄳ..

    잘못된 내용은 최대한 빨리 확인해서 고쳐놓고, 수정 보완 하겠습니다. ㅋㅋ

    이 글은 공신력있는 article 이 아니라 C++ 을 쓰던 사람이 C# 배우면서 느낌 소감문 같은겁니다.. ㅋㅋ

이름 암호 홈페이지