< Class, Object & Managed Code 3 | Main | Class, Object & Managed Code 5 >


 

 

Object-Oriented Programming:

Class, Object and Managed Code 4

 

 

What do we have in this page?

 

  1. Supplementary Notes: Some Confusing Story - Managed Extensions of C++ vs new Visual C++ .Net syntax (continue)

  2. The ^ Operator (Handle to Object on Managed Heap): Example

  3. gcnew keyword

  4. Declare Handles in Native Types: Example

 

This sample shows that a handle can be dereferenced and that a member can be accessed via a dereferenced handle.

 

// The ^ handle

// compile with: /clr

#include "stdafx.h"

 

using namespace System;

 

value struct DataCollection

{

   private:

       int Size;

       array<String^>^ x;

   public:

       DataCollection(int i) : Size(i)

       {

           x = gcnew array<String^>(Size);

           for (int i = 0 ; i < Size ; i++)

              x[i] = i.ToString();

       }

       void funct(int Item)

       {

           if (Item >= Size)

           {

              System::Console::WriteLine("Cannot access array "

                "element {0}, coz the size is {1}", Item, Size);

              return;

           }

           else

              System::Console::WriteLine("Array value: {0}", x[Item]);

       }

};

 

void funct(DataCollection y, int Item)

{ y.funct(Item); }

 

int main()

{

   DataCollection ^ aob = gcnew DataCollection(10);

   // dereference a handle, return handle's object

   funct(*aob, 7);

   // access member via dereferenced handle

   (*aob).funct(11);

   return 0;

}

 

Output:

 

C++ .Net managed class programming - a handle can be dereferenced and that a member can be accessed via a dereferenced handle

 

This sample shows that a native reference (&) can’t bind to an int member of a managed type, as the int may be stored in the garbage collected heap, and native references don’t track object movement in the managed heap. The fix is to use a local variable, or to change & to %, making it a tracking reference.

// The ^ handle example

// compile with: /clr

#include "stdafx.h"

 

using namespace System;

 

ref struct Astruct

{

   // Change the & to % to correct the error

   void Test(unsigned int &){Console::WriteLine("In Test()...");}

   void Test2(unsigned int %){Console::WriteLine("In Test2()...");}

   unsigned int i;

};

 

int main()

{

   Astruct aob;

   aob.i = 9;

   aob.Test(aob.i);   // C2664

   aob.Test2(aob.i);   // OK

 

   unsigned int j = 0;

   aob.Test(j);   // OK

   return 0;

}

 

Output:

1>.\Animal1.cpp(19) : error C2664: 'Astruct::Test' : cannot convert parameter 1 from 'unsigned int' to 'unsigned int &'

1>        An object from the gc heap (member of a managed class) cannot be converted to a native reference

Output when:

void Test(unsigned int &){Console::WriteLine("In Test()...");}

Changed to:

void Test(unsigned int %){Console::WriteLine("In Test()...");}

C++ .Net managed class programming - to illustrate that a native reference, & can’t bind to an int member of a managed type

 

gcnew

 

gcnew keyword creates an instance of a managed type (reference or value type) on the garbage collected heap. The result of the evaluation of a gcnew expression is a handle (^) to the type being created. Consider the following program example.

 

Program Example

// gcnew keyword

// compile with: /clr

#include "stdafx.h"

 

using namespace System;

 

ref struct Message

{

      System::String ^ sender, ^ receiver, ^ data;

};

 

int main()

{

   Message ^ h_Message  = gcnew Message;

 

   h_Message->sender = "Test sender";

   h_Message->receiver = "Test receiver";

   h_Message->data = "Test data";

   Console::WriteLine("sender = {0}", h_Message->sender);

   Console::WriteLine("receiver = {0}", h_Message->receiver);

   Console::WriteLine("data = {0}", h_Message->data);

   return 0;

}

 

Output:

C++ .Net managed class programming - example of the gcnew keyword that can create an instance of a managed type

 

It is possible to create an instance of a managed type, where the managed type contains a nested type other than a reference type as shown in the following program example.

// gcnew keyword

// compile with: /clr

#include "stdafx.h"

 

using namespace System;

 

ref class MyClass

{

   public:

      void Test() {Console::WriteLine("In Test(). Some string...");}

      // nested...

      value class Value_Nested_Class

      {

         public:

           int i;

      };

};

 

int main()

{

   // Instantiate new object...

   MyClass ^ h_MyClass = gcnew MyClass;

 

   MyClass::Value_Nested_Class yobj;

   yobj.i = 100;

   System::Console::WriteLine("yobj.i = {0}", yobj.i);

   return 0;

}

 

Output:

C++ .Net managed calss programming - creating an instance of a managed type, where the managed type contains a nested type other than a reference type

 

Declare Handles in Native Types

 

You cannot declare a handle type in a native type. vcclr.h provides the type-safe wrapper template gcroot, to refer to a CLR object from the C++ heap. This template lets you embed a virtual handle in a native type and treat it as if it were the underlying type. The gcroot template is implemented using the facilities of the value class System::Runtime::InteropServices::GCHandle, which provides "handles" into the garbage-collected heap. Note that the handles themselves are not garbage collected and are freed when no longer in use by the destructor in the gcroot class (this destructor cannot be called manually). If you instantiate a gcroot object on the native heap, you must call delete on that resource. The runtime will maintain an association between the handle and the CLR object, which it references. When the CLR object moves with the garbage-collected heap, the handle will return the new address of the object. A variable does not have to be pinned before it is assigned to a gcroot template.

 

Program Example

 

The following example shows how to create a gcroot object on the native stack.

// gcroot keyword

// compile with: /clr

#include "stdafx.h"

 

#include <vcclr.h>

using namespace System;

 

// native C++ class definition...

class CppClass

{

   public:

      // can use str as if it were String^

      gcroot<String^> str;

      CppClass() {}

};

 

int main()

{

   CppClass cobj;

   // using the gcnew...

   cobj.str = gcnew String("Hello dude!!!");

   // no cast required

   Console::WriteLine("cobj.str = {0}", cobj.str);

   return 0;

}

 

Output:

C++ .Net managed class programming - to show how to create a gcroot object on the native stack

 

The following working program example shows how to create a gcroot object on the native heap.

// gcroot keyword

// compile with: /clr

#include "stdafx.h"

 

#include <vcclr.h>

using namespace System;

 

// native C++ struct...

struct CppClass

{

   gcroot<String ^> * str;

   // the new and

   CppClass() : str(new gcroot<String ^>) {}

   // delete keywords, destructor...

   ~CppClass() {delete str;}

};

 

int main()

{

   CppClass cobj;

   // using the gcnew...

   *cobj.str = gcnew String("hello cutie!!!");

   Console::WriteLine("*cobj.str = {0}", *cobj.str);

   return 0;

}

 

Output:

C++ .Net managed class programming -  to show how to create a gcroot object on the native heap

 

The following sample code shows how to gcroot to hold references to value types (not reference types) in a native type by using gcroot on the boxed type.

// gcroot keyword

// compile with: /clr

#include "stdafx.h"

 

#include <vcclr.h>

using namespace System;

 

public value struct Vstruct

{

   String^ str;

};

 

class Native

{

   public:

      gcroot< Vstruct^ > v_handle;

};

 

int main()

{

   Native nativecls;

   Vstruct vobj;

   nativecls.v_handle = vobj;

   nativecls.v_handle->str = "Hello world!!!";

   Console::WriteLine("String in Vstruct: {0}", nativecls.v_handle->str);

   return 0;

}

 

Output:

C++ .Net managed class programming - to show how to gcroot to hold references to value types (not reference types) in a native type by using gcroot on the boxed type

 

 

 

 

Part 1 | Part 2 | Part 3 | Part 4 | Part 5 | Part 6 | Part 7 | Part 8

 


 

< Class, Object & Managed Code 3 | Main | Class, Object & Managed Code 5 >