Visual Studio 2010 공식 팀 블로그 @vsts2010

Posted by 흥배

 

gcnew로 생성하지 않기

 

C++/CLI는 클래스를 생성할 때 ‘gcnew’를 사용하지 않고 생성할 수도 있습니다.

 

< 리스트 1. ‘gcnew’를 사용하지 않고 클래스 생성하기 >

#include "stdafx.h"

#include <stdio.h>

 

using namespace System;

 

ref class ManagedTest

{

public:

           ManagedTest() { Console::WriteLine(L"New ManagedTest"); }

           ~ManagedTest() { Console::WriteLine(L"delete ManagedTest"); }

          

           void func() { Console::WriteLine(L"Call func() - {0}", nNumber ); }

 

           int nNumber;

};

 

void foo1()

{

           ManagedTest MTest;

           MTest.nNumber = 1;

           MTest.func();

}

 

void foo2()

{

           ManagedTest^ MTest = gcnew ManagedTest();

           MTest->nNumber = 2;

           MTest->func();

}

 

int main(array<System::String ^> ^args)

{

           foo1();

           foo2();

          

           getchar();

           return 0;

}


< 결과 >


<리스트 1> ManagedTest MTest; 는 비 관리 C++처럼 GC가 아닌 스택 영역에 생성하는 것으로 착각할 수도 있겠지만 전혀 아닙니다. 클래스를 생성하면 언제나 GC 영역에 만들어집니다.

위의 코드는 그냥 ‘gcnew’ 사용을 우리가 생략하고 컴파일러가 대신 써 준다고 생각하시면 됩니다.

 

void foo1()

{

           ManagedTest MTest;

           MTest.nNumber = 1;

           MTest.func();

}

은 컴파일러에 의해서 아래의 코드로 바뀝니다.

void foo1()

{

           ManagedTest^ MTest = gcnew ManagedTest();

           MTest->nNumber = 1;

           MTest->func();

           delete MTest;

}

 

위의 코드를 보시면 아시듯이 gcnew를 사용하지 않고 클래스를 생성하면 우리가 직접 delete를 쓰지 않아도 되는 편리함을 얻을 수 있습니다.

gcnew를 사용하지 않는 것은 C#에서 ‘using’을 간략화 시킨 것으로 생각하면 좋습니다.


< C# using 문 사용 예 >

using (Graphics g = this.CreateGraphics())

{

    g.DrawLine(Pens.Black, new Point(0,0), new Point(3,5));

}

 

 

 

 

value 클래스

 

관리 클래스는 복사 생성자와 대입 연사자를 가지지 못하므로 아래의 코드는 컴파일 에러가 발생합니다.

 

< 리스트 2. >

#include "stdafx.h"

#include <stdio.h>

 

using namespace System;

 

ref class C {

    int i;

};


void func(C c) {}


int main()

{

    C c;

    C d;

    func(c);   // 에러

    d = c;     // 에러

}

 

그러나 클래스를  ‘ref’가 아닌 ‘value’ 클래스로 정의하면 위의 코드는 컴파일 할 수 있습니다.

 

#include "stdafx.h"

#include <stdio.h>

 

using namespace System;

 

value class C {

    int i;

};

void func(C c) {}

int main()

{

    C c;

    C d;

    func(c);   // 에러

    d = c;     // 에러

}

 

value 클래스는 클래스간 복사를 할 수 있는 능력이 있습니다. 이 복사는 비트 단위의 복사로 이른바 ‘memcpy’와 같은 복사입니다.

value 클래스는 복사를 할 수 있으므로 value 클래스의 멤버는 절대 복사 가능한 멤버만 가질 수 있습니다. 그래서 아래와 같은 value 클래스 C는 컴파일 에러가 발생합니다.

 

ref class A

{

  int i;

};

 

value class C

{

  A a;

};

 

 

value 클래스의 특징으로는 ref 클래스가 GC에서 만들어지는 것과 달리 스택에 만들 수 있습니다.

value class C

{

};

 

C c;

 

위 코드에서 C 클래스는 스택에 만들어집니다(물론 gcnew를 사용하면 GC에 만들어집니다)

 

value 클래스의 특징은 좀 더 있는데 위에 설명한 것들과 포함해서 아래와 같이 정리할 수 있습니다.

 


value 클래스의 특징

 

1. 기본 생성자를 가질 수 없다.

2. 복사 생성자를 가질 수 없다.

3. 대입 연산자를 가질 수 없다.

4. 소멸자를 가질 수 없다.

5. finalize를 가질 수 없다.

6. 클래스간 복사를 할 수 있다.

7. 복사 불가능한 것을 멤버로 가질 수 없다(ref 클래스 등).

8. 스택에 생성할 수 있다.

9. 다른 클래스를 계승할 수 없다( interface는 가능하다)

 

 

 


관리 클래스를 파라메터로 넘기기

 

ref class A

{

           int i;

};

 

void foo1( A a )

{

}

 

함수 foo1의 파라미터 정의는 클래스 A value 클래스일 때만 사용할 수 있습니다. 그러므로 아래와 같이 foo1의 파라미터를 정의해야 합니다.

void foo1( A^ a )

{

}

 

 

 

 

그 외….

 

C++/CLI에서 참조는 ‘%’을 사용합니다. 이것은 비 관리의 ‘&’와 구별이 됩니다.

%는 아래와 같은 경우에 유용하게 사용할 수 있습니다.

void foo( A^ a )

{

}

 

A a;

// foo( a );  // 에러

foo( %a ); // 성공


참조는 C#에서는 'ref', VB.NET에서는 'ByRef'와 같다고 생각하시면 됩니다.


// 값을 참조로 넘기는 경우

void valuebyref(int%i)
{
   i=5;
}

// 참조형을 참조로 넘기기
void refbyref(String^%s)
{
   s="newstring";
}

void main()
{
   int i=1;

   valuebyref(i);

   String^s="basestring";
   refbyref(s);
}
( 위 코드는 http://adversaria-june.blogspot.com/2006/08/ccli_26.html 에서 인용했습니다 )

 



구조체


C++/CLI에서의 구조체가 클래스와 다른 점

1. 'value class'와 같습니다. 물론 비 관리코드에서는 기존의 C++과 같다

2. 구조체는 상속 받을 수 없다.

 

 

 

 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. 좋은정보 감사합니다. :)

  2. 흥배님 위에 코드가 잘못된 거 같습니다. 에러가 납니다. 확인해주세요.

    ref class A
    {
    int i;
    };

    // C++/CLI에서 참조는 '%'을 사용합니다(이것은 비 관리의 '&'와 구별이 됩니다)
    void foo(A^ a)
    {

    }

    A a;

    //foo(a); // 에러
    foo(%a); // 성공

  3. 흥배님 value 클래스부터 밑으로 전부 컴파일이 안 됩니다. 확인해보셨던 솔루션 메일로 보내주세요. giraffe9@gmail.com으로 부탁합니다.

    #include "stdafx.h"

    void valuebyref(int% i)
    {
    i = 5;
    }

    void refbyref(String^% s)
    {
    s = "newstring";
    }

    void main()
    {
    int i = 1;

    valuebyref(i);

    String^ s = "basestring";
    refbyref(s);
    }

    //ref class A
    //{
    // int i;
    //};
    //
    //void foo(A^ a)
    //{
    //}
    //
    //A a;
    //foo(%a);


    //ref class A
    //{
    // int i;
    //};
    //
    //void foo(A^ a)
    //{
    //}
    //
    //A a;
    //foo(a);


    //ref class A
    //{
    // int i;
    //};
    //
    //void foo1(A^ a);
    //{
    //}


    //ref class A
    //{
    // int i;
    //};
    //
    //void foo1(A a);
    //{
    //}


    //value class C
    //{
    //};
    //
    //C c;


    //ref class A
    //{
    // int i;
    //};
    //
    //value class C
    //{
    // A a;
    //};


    //#include <stdio.h>
    //
    //using namespace System;
    //
    //class C
    //{
    // int i;
    //};
    //
    //void func(C c) {}
    //
    //int main()
    //{
    // C c;
    // C d;
    // func(c);
    // d = c;
    //}


    //#include <stdio.h>
    //
    //using namespace System;
    //
    //ref class C
    //{
    // int i;
    //};
    //
    //void func(C c) {}
    //
    //int main()
    //{
    // C c;
    // C d;
    // func(c);
    // d = c;
    //}

  4. 흥배님 마지막 소스코드가 빌드되지 않습니다.
    어떻게 바꿔야 할까요?

    // 값을 참조로 넘기는 경우
    void valuebyref(int% i)
    {
    i = 5;
    }

    void refbyref(String^% s)
    {
    s = "newstring";
    }

    void main()
    {
    int i = 1;

    valuebyref(i);

    String^ s = "basestring";
    refbyref(s);
    }