< C++ .Net Early Stages 10 | Main | C++ .Net Early Stages 12 >


 

 

Early Stages of the (Visual) C++ .Net 11

(Managed Extensions for C++)

 

 

In this module we start to see some of the C++ .Net implementation using VC++ 2003. Notice the new deprecated keywords used. The following are the topics for this module. The code snippets used in this module are for Visual C++ .Net 2003 and if compiled using Visual C++ .Net 2005 you need to use the /clr:oldSyntax option).

  1. Implementing .NET Types

  2. Namespaces

---------Next Page-----------------

  1. Inheritance

  2. Exporting and Importing Types

  3. Visibility

  4. Member Access

  5. Nested Types

  6. Using Types from Other Languages

  7. Casts and Conversions

  8. Cast Operators

  9. Conversion Operators

 

 

 

  1. Managed Operators

  2. Unary Operators

  3. Binary Operators

  4. Creating and Destroying Objects

  5. Entry Points

  6. Summary

 

Implementing .NET Types

 

So far we have explained the basic features of .NET, how they relate to C++, and how to implement them in managed C++. In this section, we will look at details of implementing hierarchies of .NET objects in C++.

 

The Namespaces

 

Both C++ and .NET use namespaces for expressing logical grouping. Declaring a namespace is straightforward, as shown here:

namespace RTG

{

   namespace Diagnostics

   {

      __gc class Log {};

   }

}

This code declares a class with the .NET name of RTG.Diagnostics.Log. Note that we say this is the .NET name of the class: if you get the type object of the class and call ToString, you’ll get RTG.Diagnostics.Log with dots separating the items in the name.

Type* t = __typeof(RTG::Diagnostics::Log);

 

Console::WriteLine(t->ToString());  // prints RTG.Diagnostics.Log

Console::WriteLine(t->Namespace);   // prints RTG.Diagnostics

Console::WriteLine(t->Name);        // prints Log

A working example is shown below.

 

 

// This is the main project file for VC++ application project

// generated using an Application Wizard.

// Visual C++ .Net 2003

#include "stdafx.h"

#using <mscorlib.dll>

using namespace System;

 

namespace RTG

{

   namespace Diagnostics

   {

      __gc class Log {};

   }

}

 

void main()

{

  Type* t = __typeof(RTG::Diagnostics::Log);

 

  Console::WriteLine(t->ToString());  // prints RTG.Diagnostics.Log

  Console::WriteLine(t->Namespace);   // prints RTG.Diagnostics

  Console::WriteLine(t->Name);        // prints Log

}

 

Visual C++ .Net program output sample

 

The Log class is declared in the RTG::Diagnostics namespace. To declare aggregated names like this, you have to use this nested syntax; you can declare types in the outer declared namespaces.

namespace RTG

{

   __gc class Utility{};

 

   namespace Diagnostics

   {

      __gc class Log{};

   }

}

Now we have two namespaces, RTG and RTG::Diagnostics. To use a class, you have to use the C++ name.

RTG::Diagnostics::Log* log  = new RTG::Diagnostics::Log;

This requirement is true of the classes that you define and of .NET Framework classes. C++ provides several ways to reduce your typing for example, you can use the using statement to indicate the default namespace for the compiler to check for items, as shown here:

using namespace RTG;

using namespace RTG::Diagnostics;

Again, the name is the C++ name for the namespace, not the .NET name. Incidentally, you cannot split namespaces, so although we have used using on the namespace RTG, we cannot refer to Log as Diagnostics::Log. C++ allows you to define namespace aliases.

// This is the main project file for VC++ application project

// generated using an Application Wizard.

// Visual C++ .Net 2003

#include "stdafx.h"

#using <mscorlib.dll>

using namespace System;

 

namespace interop = System::Runtime::InteropServices;

 

void main()

{

   int bytes = interop::Marshal::SystemDefaultCharSize;

   Console::WriteLine(S"Characters on this system are {0} bytes", __box(bytes));

}

 

Console mode .Net output sample

 

Here we have defined interop as an alias for a .NET namespace, which saves me typing a long line to access the static property Marshal::SystemDefaultCharSize, but it also protects us because we are using the fully qualified name. C++ also allows you to group classes from different namespaces in a new namespace.

namespace Utility

{

   using interop::Marshal;

   using System::Type;

}

Now we can call Marshal and Type through the new namespace Utility. However, this strategy is confusing, especially for .NET Framework classes.

Namespaces are logical groupings. They do not give an indication of the actual location of the code. Namespaces can span assemblies for example, most of the classes in the System namespace are in the mscorlib assembly, but other types in the namespace are implemented in other assemblies. For example, the System::Uri class is implemented in the System assembly, so if you want to use this class, you have to make sure that you have an appropriate #using statement. If you compile code and you get errors that certain types are undeclared identifiers, you have two possible reasons: either the compiler cannot find the type from the namespaces mentioned in the using namespace statements you have given (test this possibility by using the fully qualified name for the type), or you do not have the metadata for the type. In the latter case, you have to check the documentation to determine the assembly in which the type is implemented. Consider this example:

// This is the main project file for VC++ application project

// generated using an Application Wizard.

// Visual C++ .Net 2003

#include "stdafx.h"

 

#using <mscorlib.dll>

 

void main()

{

   System::Uri* url = new System::Uri(S"http://www.microsoft.com");

   System::Console::WriteLine(S"The host is {0}", url->Host);

}

.Net console mode program output example

 

This code will not compile. The compiler will give errors indicating that Uri is an undeclared identifier. Because we use fully qualified names, the problem must be due to metadata. In fact, the Uri class is implemented in the system assembly, so the errors will go away if we add this line to the source file:

#using <system.dll>

 

 

 

Part 1 | Part 2 | Part 3 | Part 4

 


 

< C++ .Net Early Stages 10 | Main | C++ .Net Early Stages 12 >