사용자 도구

사이트 도구


사이드바

language:cpp:managedcpp
vsts2010.net 없어졌네요. 

VisualStudio2010 블로그를 읽다가 정리한 것 뿐입니다.

클래스 선언

Managed 클래스 구조체 선언은 {class, struct} 앞에 {ref, value, interface, enum} 중에 다른 것을 하나 붙여서 사용.

Native와 같이 사용 되는 경우, 구분 짓기 위해서 그런 것 같다. ( 그렇다면 그냥 클래스를 사용하는 것도 가능? )

class_access ref class name modifier : inherit_access base_type {};
  • ref class, ref sturcut : 인터페이스나 ref type에서 상속 받는 경우 –> 안전빵?
  • value ref, value struct : 인터페이스에서만 상속 받는 경우
  • value 는 아래 줄을 좀 더 읽어보는게 도움이 됨

^

ref 로 선언한 관리클래스는

  • GC에서 동적으로 생성/관리된다.
  • 정적은 안된다.
  • ^ 로 핸들을 선언해야한다. (GC 계열 언어들이 늘 그런듯이 메모리를 할당하는 것이 기본)
  • delete를 사용할 수 있는데, 클래스 내부 리소스 해제용이지 클래스의 메모리가 (핸들이) 삭제되는 것은 아니다.
  • finalize 를 선언해서 GC에서 소멸될 때 할일의 적는다.
    • 키워드 : !
  • 한글레퍼런스 http://vsts2010.net/314
ref class SampleClass 
{
public:
    SampleClass() {}
    ~SampleClass() {}
    !SampleClass() {}    
};

//코드
{
    SampleClass^ _a = gcnew SampleClass();
}

value 와 참조

  1. 한글레퍼런스 http://vsts2010.net/323
  2. gcnew를 쓰지 않고 코드를 작성하는 경우, 컴파일러가 알아서 바꿔줍니다.

value

  1. ref 로 선언된 관리클래스는 복사 기능이 없음
  2. value로 선언하면 복사가 가능한 기본 타입에 대해서 복사 작업이 가능
  3. gcnew 로 생성하지 않으면 스택에 생성됨 - 함수 종결시 소멸?이라는 뜻인가.

value 특징

  1. 기본 생성자가 없다.
  2. 복사 생성자를 가질 수 없다
  3. 대입 연산자를 가질 수 없다.
  4. 소멸자를 가질 수 없다.
  5. finalize를 가질 수 없다.
  6. 클래스간 복사를 할 수 있다.
  7. 복사 불가능한 것을 멤버로 가질 수 없다.
  8. 스택에 생성할 수 있다.
  9. 인터페이스를 제외한 다른 클래스를 계승할 수 없다.

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

  1. 파라미터에 ^ 를 붙여야 한다.
    void func( A^ a ) {} 

참조

  1. '&' 사용

nullptr/interior_ptr

nullptr

  • 관리 클래스에는 0 (NULL) 대신 nullptr 을 씁니다.

interior_ptr

  • 네이티브 C++에서 처럼 코드의 일부의 포인터를 넘겨줄 때 씁니다.

pin_ptr

  • 비관리코드에서 포인터로 사용하고 싶을때 사용합니다.
    C++/CLI에서 기존의 비관리 코드로 만들어 놓은 라이브러리를 사용할 때입니다
    ref class REFClass {
    public: int nValue;
    };
    
    void SetValue( int* pValue )
    {
        *pValue = 100;
    }
     
    int main()
    {
        REFClass^ refClass = gcnew REFClass;
        pin_ptr<int> pValue = &refClass->nValue;
        SetValue( pValue );
        pValue = nullptr;
    }
  • 사용 후에는 nullptr로 초기화(unpin)하는게 좋다고 합니다.

array 클래스에 non-CLI 오브젝트 사용

array 클래스 생성 할때는 포인터 타입으로 선언해 주어야 합니다. (어찌보면 당연한??)

class CNative { /* sample class */ };
// other func
{
 
    array< CNative* >^ _arr = gcnew array< CNative* >(2);
    array< CNative >^ _arr = gcnew array< CNative >(2);
}

사용할때는 직접 메모리를 할당해줘야 합니다.

for(int i=0; i<arr->Length; i++)
{
    arr[i] = new CNative();
}

또한 당연하지만, 삭제할 때도 직접 삭제해 줘야한다. GC 가 삭제해 주지 않는다.

for( int i = 0; i < arr->Length; i ++ )
{
    delete arr[i]; 
}

델리게이트에 비관리함수 할당해서 사용하기

이건 거의 팁이군요. 그래도 알면 요긴하게 쓸 수 밖에 없는 팁인 듯.

물론 코드는, vsts2010.net 에서 가져왔습니다.

#pragma unmanaged
 
extern "C" void printf(const char*, ...);
 
class A
{
// 꼭 static 을 써야 하는 건지??
public:  void func(char* s) { printf(s); }
};
 
#pragma managed
 
public delegate void func(char*); 
 
ref class B
{
public:
    A* ap;
    B(A* ap):ap(ap) {}
 
    void func(char* s) { ap->func(s); }
};
 
int main()
{
    A* a = new A;
    B^ b = gcnew B(a);
    func^ f = gcnew func(b, &B::func);
    f("hello");
    delete a;
}

순 가상함수

=0 대신 abstract 를 사용

순 가상함수를 추가하면 클래스도 순 가상 클래스가 될 필요가 있으므로 클래스에도 abstract 를 붙입니다.

public ref class Server abstract
{
   .....
 
   virtual void OnAccept() abstract;
};

char* -> 관리코드, 관리코드 -> char*

이것도 꽤 요긴할 것 같네요. C++/CLI 마샬링은 요기 (Overview of Marshaling in C++ )에 잘 나와 있습니다.

블로그 내용을 그대로 가져왔습니다.

char* -> 관리코드

// 비관리코드
int nPacketSize = 34;
char* pPacket = new char[34];
 
// 관리코드
array< Byte >^ byteArray = gcnew array< Byte >(nPacketSize);
System::Runtime::InteropServices::Marshal::Copy( (IntPtr)pPacket, byteArray, 0, nPacketSize );

관리코드 -> char*

// 관리코드
array<Byte>^ SendData;
 
// 비관리코드
int nLength = SendData->Length;
pin_ptr<Byte> pData = &SendData[0];
char* pBuffer = new char[ nLength ];
CopyMemory( pBuffer, pData, nLength );

참고로 C++/CLI에서는 바이트형 배열 array<Byte>가 C#에서는 byte[] 이 됩니다.

legacy

language/cpp/managedcpp.txt · 마지막으로 수정됨: 2019/01/16 19:00 저자 kieuns