C++/CLI Type




■ C++/CLI Data Type

C++/CLI 는 3가지 데이터 타입을 가지고 있다.

    - Refercence Type
    - Value Type
    - Native Type



Native Type
C++ 이 가지고 있는 타입으로써 int, float, class, struct, 등이 있다.
타입 인스턴스의 메모리는 스택에 할당된다.
new 연산자로 동적 메모리 생성 하면 힙에 할당 된며, 메모리 해제는 프로그래머의 책임이다.

Value Type & Reference Type
Managed 환경의 Data Type 으로 모두 System::Object 클래스로 부터 상속받아 구현된다.
System::Object 가 외부로 노출시킨 메소드는 다음과 같다.

 Method Name  Return Value  Accssibility
 Equals  bool  public
 GetType  Type  public
 ToString  System::String^  public
 GetHashCode  int  public
 Finalize  -  protected
 MembewiseClone  System::Object^  protected
 ReferenceEquals  bool  public static


Value Type 은 System::ValueType 으로 부터 상속 받는다. System::ValueType 은 System::Object 를 상속 받는다. Value Type 은 메모리를 항상 스택에 할당한다. 모든 Primitive Data Type 과 Struct 들은 Value Type 이다.





■ Primitive Types Mapping

 Data Type Name  Type C++/CLI Keyword
 16bit Integer  System::Int16  short
 32bit Integer  System::Int32  int
 64bit Integer  System::Int64  __int64, long long
 Double  System::Double  double
 Character [2 bytes]  System::Char  char
 Character [1 byte]  System.Byte  byte
 Boolean  System.Boolean  bool

※ 이 밖에도 많은 타입이 정의되어 있다.
※ Primitive Type 은 Value Type 으로서 Stack 에 메모리 할당 된다.
※ Native Code 와 C++/CLI 간의 Primitive Type 값 변환은 별도의 조작없이 바로 해주면 된다.

Primitive Type 의 선언과 사용 예





C++/CLI 에서 Primitive Data Type 은 Value Type 으로서 .NET 의 Primitive Data Type 을 사용하는 방법과 동일하다.





■ Class & Struct

 Native Data Type  Managed Data Type
 class  ref class
 struct  value struct
 enum  enum class
 std::string  String^
 std::map  Dictionary^
 std::vector  List^
 std::list  List^
 function pointer  delegate


C++/CLI 에서 클래스는 Reference Type (.NET Framework 에서 클래스는 Reference Type 이므로 당연한 소리)  이다. Reference Type 의 인스턴스는 결코 스택에 할당되지 않는다. Reference Type 의 인스턴스는 힙에 할당된다. 그러나 이 힙은 Managed Heap 이라 불리며 Native type 이 사용하는 힙과는 다르다. "new" 키워드는 Native Heap 에 메모리를 할당하며, "gcnew" 는 Managed Heap 에 메모리를 할당한다. gcnew 를 사용하여 선언하는 방법은 다음과 같다.



위 방법은 C++/CLI 에서 Managed 객체를 생성하는 방법이다. Managed Heap 에 생성된 인스턴스에 접근하기 위해서는 "객체 참조 (Object Reference)" 또는 "Handle" 이라 불리는 것(위의 코드에서 objRef)을 통하여 접근 가능한데 이들은 스택에 할당된다. 객체 참조를 통하지 않고서는 인스턴스에 접근할 수 없다. 본질적으로 객체 참조는 주소를 물고 있다. 하지만 Native Code 의 포인터와는 같지 않다. 객체 참조는 포인터와 다르게 포인터 연산을 할 수 없다. Managed Heap 에 인스턴스는 하나 이상의 Reference 를 갖는다. 따라서 다른 객체로 객체 참조 shallow copy 가 가능하다. 
 .NET Framework 의 CLR 은 매우 영리하며, Garbage Collection 이 있기 때문에 프로그래머가 메모리 해제에 대해서 걱정할 필요가 없다. 하지만 Database open 과 같이 사용자가 할당한 메모리에 대해서는 사용자가 책임지고 메모리 해제 작업을 해주어야 한다.  다음은 C++/CLI 의 클래스 예 이다.



※ ref class
ref class 로 선언하게 되면 Managed Code 가 되어 가비지 컬렉터의 관리를 받게 된다.
ref class 로 선언되지 않은 클래스는 가비지 컬렉터의 관리를 받지 않으며 Unmanaged Code 이다. 따라서 일반 클래스로 동적 메모리 생성을 하였다면 직접 메모리를 해제시켜 주어야 한다.


※ ref class 작성 예



※ Destructor (소멸자)
일반적인 클래스와 마찬가지로 ref class 역시 소멸자가 존재한다. 또한 사용하는 방법 역시 똑같다. 하지만 ref class 의 소멸자는 IDisposable 인터페이스를 구현한 후에 컴파일러가 소멸자의 호출을 Dispose() 호출로 번역한다. 또한 finalizer 호출이 있는데 이는 Gabage Collector 에 의해 호출되며 "!MyClass()" 와 같이 정의된다. finalizer 는 소멸자가 호출되었는지 확인한 다음에 호출되지 않았다면 소멸자를 호출시켜준다.





■ Declaring and Consuming a Managed Class

1. 전형적인 방법


위 코드에서 caret [^] 는 변수 sysDir 이 Reference 인스턴스를 가리키고 있는 객체 참조 임을 나타낸다. 객체 참조를 통하여 클래스의 public 메소드를 호출할 수 있고, 또다른 객체 참조로 복사할 수 있다. ^ 으로 선언한 객체 참조는 gcnew 키워드를 통하여 Managed Heap 에 메모리 할당 되며 이 메모리는 Garbage Collector 의 관리를 받는다.


2. shallow copy


Managed Heap 에 생성된 Reference 참조를 sysDir 객체 참조가 가리키고 있는데, sysDir2 역시 같은 곳을 가리키게 하는 방법이다.


3. Invoke method


객체 참조 sysDir 을 이용하여 public 메소드를 호출(Invoke) 하는 방법이다.


4. 객체 참조의 매개변수로의 전달


 메소드의 매개변수로 객체 참조가 전달 되었다. 이 메소드 안에서 똑같은 객체에 대해서 작업할 수 있다. 객체 참조가 전달 될 때 복사 생성자는 호출되지 않는다. 즉, 객체의 복사본은 생성되지 않는다. 이것은 C++ 의 포인터를 넘겨 주는 방법과 비슷하다. 만약 복사본을 생성해야 한다면 당신이 작성한 클래스는 System::IClonalbe 인터페이스를 상속 받아야 하고, Clone() 메소드를 구현해야 한다.


5. 객체 참조의 리턴


위의 코드결과 Directory 객체가 생성된다. 할당된 인스턴스를 가리키고 있는 객체 참조가 리턴된다. 리턴된 후에 dirObj 는 Managed Heap 에 있는 객체를 더이상 가리키지 않는다. 리턴되는 객체 참조를 할당 받고, 그것을 보존하는 것은 메소드를 호출하는 쪽의 책임이다.





■ Abstract Class

클래스에 abstract 키워드를 붙이면 Managed Class 를 추상 클래스로 만든다. 이 방법은 추상 메소드(순수 가상 메소드) 선언 없이 클래스를 추상화 시키는 편리한 방법이다. 또한 메소드는 abstract 키워드로 선언된다.









■ 생성자
C++/CLI 클래스의 생성자는 기본 인수(Default parameter)를 가질 수 없다.
namespace ManagedMemFileEx
{
	public ref class CCliMemFileEx
	{
    public:
        explicit CCliMemFileEx(System::UInt32 _nGrowBytes = 1024);
        virtual ~CCliMemFileEx();
    };
}

위와 같이 기본 인자를 가진 생성자를 정의하면 다음과 같은 에러 메시지를 출력 한다.

"오류 1 error C3222: '_nGrowBytes' : 제네릭 함수 또는 관리되는 형식의 멤버 함수에 대한 기본 인수를 선언할 수 없습니다."





■ 참조
1. C++/CLI Primer - Enter the World of .NET Power Programming (CodeProject)
2. Quick C++/CLI - Learn C++/CLI in less than 10 minutes (CodeProject)

Posted by six605
,