Introduction to C++/CLI

  Windows IT Pro
Windows IT Library
  - Advertise        
Windows IT Pro Logo

  Home  |   Books  |   Chapters  |   Topics  |   Authors  |   Book Reviews  |   Whitepapers  |   About Us  |   Contact Us  |   ITTV  |   IT Jobs

search for  on    power search   help
 






Introduction to C++/CLI
View the book table of contents
Author: Nishant Sivakumar
Published: April 2007
Copyright: 2007
Publisher: Manning Publications Co.
 


In this chapter, you’ll see what C++/CLI can be used for and how C++/CLI improves the now-obsolete Managed C++ syntax. We’ll also go over basic C++/ CLI syntax. By the end of this chapter, you’ll know how to write and compile a C++/CLI program and how to declare and use managed types. Some of the new syntactic features may take a little getting used to, but C++ as a language has never had simplicity as its primary design concern.
 

When C++ was wedded to CLI with a slash, it was apparent from the beginning that it wasn’t going to be a celebrity marriage. The world’s most powerful high level programming language—C++—was given a face-lift so that it could be used to develop on what could potentially be the world’s most popular runtime environment: the CLI. 

In this chapter, you’ll see what C++/CLI can be used for and how C++/CLI improves the now-obsolete Managed C++ syntax. We’ll also go over basic C++/ CLI syntax. By the end of this chapter, you’ll know how to write and compile a C++/CLI program and how to declare and use managed types. Some of the new syntactic features may take a little getting used to, but C++ as a language has never had simplicity as its primary design concern. Once you get used to it, you can harness the power and ingenuity of the language and put that to effective use.


1.1 THE ROLE OF C++/CLI

C++ is a versatile programming language with a substantial number of features that makes it the most powerful and flexible coding tool for a professional developer. The Common Language Infrastructure (CLI) is an architecture that supports a dynamic language-independent programming model based on a Virtual Execution System. The most popular implementation of the CLI is Microsoft’s .NET Framework for the Windows operating system. C++/CLI is a binding between the standard C++ programming language and the CLI. Figure 1.1 shows the relationship between standard C++ and the CLI.

C++ has been paired with language extensions before, and the result hasn’t always been pretty. Visual C++ 2005 is the first version of a Microsoft C++ compiler that has implemented the C++/CLI specification. This means three things for the C++ developer:
  • C++ can be used to write applications that run on the .NET Framework. There is no need to learn a totally new language or to abandon all the C++ knowledge and experience built up through years of coding.
  • C++/CLI lets developers reuse their native C++ code base, saving the agony of having to rewrite all the existing code to enable it to run on the .NET Framework.
  • C++/CLI is designed to be the lowest-level language for the .NET Framework. For writing purely managed applications, it’s your most powerful choice; or, as I like to say, "C++/CLI actually lets you smell the CLR (Common Language Runtime)."
Visual C++ 2005 isn’t Microsoft’s first attempt at providing a C++ compiler capable of targeting managed code. Both VC++ 2002 and VC++ 2003 featured a C++ compiler that supported the managed extensions to C++ (referred to as Managed C++ or MC++). As a syntactic extension, it would be an understatement to say that it was a comprehensive failure.

Now that you understand the role of C++/CLI, let’s examine why it’s such an invaluable inclusion among CLI languages.

The .NET Framework

It’s important for you to have a basic understanding of the .NET Framework, because although this book will teach you the C++/CLI syntax before we move on to various interop mechanisms and strategies, it doesn’t attempt to teach you the core details of the .NET Framework. If you’ve never used the .NET Framework, you should read the book’s appendix ("A Concise Introduction to the .NET Framework") before you proceed further. On the other hand, if you’ve previously worked with the .NET Framework, you can refresh your memory by looking at these quick definitions (in no particular order) of various terms associated with the .NET Framework, which you’ll encounter in this and other chapters:
  • .NET Framework: The .NET Framework is Microsoft’s implementation of the Common Language Infrastructure (CLI), which itself is an open specification that has been standardized by the ECMA (an international standards body). The .NET Framework consists of the Common Language Runtime (CLR) and the Base Class Library (BCL).
  • CLR: The Common Language Runtime is the core of the .NET Framework and implements the fundamental aspects of the CLI such as the Virtual Execution System (VES), the Garbage Collector, and the Just in Time (JIT) compiler.
  • BCL: The Base Class Library is an extensive set of .NET classes that is used by any .NET language (such as C#, VB.NET, C++/CLI, and so on).
  • VES: The Virtual Execution System is the engine responsible for executing managed code, including the invocation of the Garbage Collector as well as the JIT compiler.
  • Garbage Collector: Memory management is automatically done in the .NET Framework. The CLR includes a Garbage Collector that frees resources when they’re no longer needed, so the developer doesn’t need to worry about that.
  • JIT compiler: .NET compilers (C#, VB.NET, C++/CLI, and so on) compile source code into an intermediate language called Microsoft Intermediate Language (MSIL). At runtime, the CLR uses the JIT compiler to compile this MSIL into the native code for the underlying operating system before executing it.
  • CTS: The Common Type System (CTS) is a set of rules that specifies how the CLR can define, use, create, and manage types.
  • CLS: The Common Language Specification (CLS) is a subset of the CTS that all languages must implement if they’re to be considered CLS-compliant. CLScompliant languages can interop with each other as long as they don’t use any non-CLS-compliant features present in their specific compiler version.
I’d like to reiterate that if you’re not familiar with these terms, or if you wish to understand them in more detail, please take a detour into the appendix, where most of these concepts are explained more thoroughly.½

1.1.1 What C++/CLI can do for you

If you’re reading this book, chances are good that you’re looking to move your applications to the .NET Framework. The biggest concern C++ developers have about making the move to .NET is that they’re afraid of abandoning their existing native code and having to rewrite everything to managed code. That’s exactly where C++/CLI comes into the picture. You do not have to abandon your current native code, nor do you have to rewrite everything to managed code. That’s C++/ CLI’s single biggest advantage—the ability to reuse existing native code.

Reuse existing native code
Visual C++ 2005 allows you to compile your entire native code base to MSIL with the flick of a single compilation switch. In practice, you may find that you have to change a small percentage of your code to successfully compile and build your applications. This is a far better option than either abandoning all your code or rewriting it entirely. Once you’ve successfully compiled your code for the CLR, the code can access the thousands of classes available in the .NET Base Class Library.

Access the entire .NET library
The .NET Framework comes with a colossal library containing thousands of classes that simplify your most common developmental requirements. There are classes relating to XML, cryptography, graphical user interfaces, database technologies, OS functionality, networking, text processing, and just about anything you can think of. Once you’ve taken your native applications and compiled them for the CLR, you can use these .NET classes directly from your code. For example, you can take a regular MFC dialog-based application and give it some encryption functionality using the .NET cryptography classes. You aren’t restricted to managed libraries, because C++/CLI lets you seamlessly interop between managed and native code.

Most powerful language for interop
Although other languages like C# and VB.NET have interop features, C++/CLI offers the most powerful and convenient interop functionality of any CLI language. C++/CLI understands managed types as well as native types; consequently, you often end up using whatever library you want (whether it’s a native DLL or a managed assembly) without having to worry about managed/native type conversions. Using a native library from C++/CLI is as simple as #include-ing the required header files, linking with the right lib files, and making your API or class calls as you would normally do. Compare that with C# or VB.NET, where you’re forced to copy and paste numerous P/Invoke declarations before you can access native code. In short, for any sort of interop scenario, C++/CLI should be an automatic language choice. One popular use of interop is to access new managed frameworks such as Windows Forms from existing native applications. (Note that this technique is covered in detail in part 3 of the book.)

Leverage the latest managed frameworks
Imagine that you have a substantially large MFC application and that your company wants to give it a new look and feel. You’ve recently acquired an outstanding Windows Forms–based UI library from another company. Take VC++ 2005, recompile the MFC application for the CLR, and change the UI layer to use the Windows Forms library, and now you have the same application that uses the same underlying business logic with the new shiny user interface. You aren’t restricted to Windows Forms or even to UI frameworks. The next version of Windows (called Windows Vista) will introduce a new UI framework called the Windows Presentation Foundation (WPF). It’s a managed framework and C++/CLI will let you access it from existing native applications. When Vista is released, your applications will be able to flaunt the WPF look and feel. Note that WPF is also being made available for Windows XP, so you aren’t restricted to using Vista to run WPF-based applications.

Another powerful managed framework that is coming out in Vista is the Windows Communication Foundation (WCF), which, as the name implies, is a powerful communication framework written in managed code. And yes, although you knew I was going to say it, you can access the WCF from your Visual C++ applications. Although native code reuse and powerful interop are its most popular advantages, C++/CLI is also your most powerful option to write managed applications.

Write powerful managed applications
When Brandon Bray from the Visual C++ Compiler team said that C++/CLI would be the lowest-level language outside of MSIL, he meant what he said! C++/ CLI supports more MSIL features than any other CLI language; it is to MSIL what C used to be to Assembly Language in the old days. C++/CLI is currently the only CLI language that supports stack semantics and deterministic destruction, mixed types, managed templates, and STL.NET (a managed implementation of the Standard Template Library).

A natural question you may have now is why Microsoft introduced a new syntax. Why didn’t it continue to use the old MC++ syntax? That’s what we examine next.

1.1.2 The rationale behind the new syntax

The managed extensions to C++ introduced in VC++ 2002 were not well received by the C++ developer community. Most people appreciated the fact that they could use C++ for .NET development, but almost everybody thought the syntax was gratuitously twisted and unnatural, that the managed and unmanaged pointer usage semantics were confusing, and that C++ hadn’t been given equal footing as a CLI language with other languages like C# or VB.NET. Another factor that contributed to poor Managed C++ acceptance was the fact that designer support for Windows Forms was not available in the 2002 release; although the 2003 release did introduce a designer, it wasn’t as stable or functional as the designers available for C# and VB.NET, and creating pure managed applications was dreadfully unfeasible with C++.

Microsoft took the feedback from its C++ developer community seriously, and on October 6, 2003, the ECMA (an association dedicated to the standardization of Information and Communication Technology and Consumer Electronics) announced the creation of a new task group to oversee the development of a standard set of language extensions to create a binding between the ISO standard C++ programming language and the CLI. Microsoft developed and submitted full draft specifications for binding the C++ Programming Language to the Common Language Infrastructure in November 2003, and C++/CLI became an international ECMA standard in December 2005. It was expected that the ECMA would submit it to the ISO for consideration as a potential ISO standard. Visual C++ 2005 is the first publicly available compiler to support this new standard.

NOTE:
The ECMA (the acronym originally stood for European Computer Manufacturers Association) is an association founded in 1961 that’s dedicated to the standardization of Information Technology systems. The ECMA has close liaisons with other technology standards organizations and is responsible for maintaining and publishing various standards documents. Note that the old acronym isn’t used anymore, and the body today goes by the name ECMA International. You can visit its website at www.ecma-international.org.

Let’s take a quick look at a few of the problems that existed in the old syntax and how C++/CLI improves on these issues. If you’ve used the old syntax in the past, you’ll definitely appreciate the enhancements in the new syntax; if you haven’t, you’ll still notice the stark difference in elegance between the two syntaxes.

Twisted syntax and grammar
The old Managed C++ syntax used a lot of underscored keywords that were clunky and awkward. Note that these double-underscored keywords were required to conform to ANSI standards, which dictate that all compiler-specific keywords need to be prefixed with double underscores. But as a developer, you always want your code to feel natural and elegant. As long as developers felt that the code they wrote didn’t look or feel like C++, they weren’t going to feel comfortable using that syntax; most C++ developers chose not to use a syntax that felt awkward.

C++/CLI introduced a new syntax that fit in with existing C++ semantics. The elegant grammar gives a natural feel for C++ developers and allows a smooth transition from native coding to managed coding.

Look at Table 1.1, which compares the old and new syntaxes; you’ll see what I mean.

Even without knowing the rules for either the old or the new syntax or C++/ CLI, you shouldn’t find it hard to decide which is the more elegant and natural of the two. Don’t worry if the code doesn’t make a lot of sense to you right now. Later in this chapter, we’ll go through the fundamental syntactic concepts of the C++/ CLI language. I just wanted to show you why the old syntax never became popular and how Microsoft has improved on the look and feel of the syntax in the new C++/CLI specification.

With the old syntax, every time you used a CLI feature, such as a delegate or a property, you had to prefix it with underscored keywords. For a property definition, the old syntax required separate setter and getter blocks and didn’t syntactically organize them into a single block. This meant that if you carelessly separated the getter and setter methods with other code, there was no visual cue that they were part of the same property definition. With the new syntax, you put your getter and setter functions inside a property block; the relationship between them is visually maintained. To summarize my personal thoughts on this issue, with the old syntax, you feel that you’re using two unrelated sublanguages (one for managed code and one for native code) with a single compiler. With the new syntax, you feel that you’re using C++, albeit with a lot of new keywords: It’s still a single language. Note that the VC++ team made an effort to ensure that the new keywords don’t interfere with existing code bases, as you’ll see later in the book.

Programmers can be compiler snobs. Many developers opined that C# and VB.NET were proper .NET languages, whereas MC++ was a second-class citizen compared to them. Let’s see what has been done to the C++ language to promote it to a first-class CLI status.

Second class CLI support
Managed C++ seemed like a second-class CLI language when compared to languages like C# and VB.NET, and developers using it had to resort to contorted workarounds to implement CLI functionality. Take a trivial example such as enumerating over the contents of an ArrayList object. Here’s what the code would look like in Managed C++:
IEnumerator* pEnumerator = arraylist->GetEnumerator();
while(pEnumerator->MoveNext())
{
Console::WriteLine(pEnumerator->Current);
}
While languages like C# provided a for each construct that abstracted the entire enumeration process, C++ developers were forced to access the IEnumerator for the ArrayList object and use that directly—not a good thing, as far as Objected- Oriented abstraction rules were concerned. Now the programmer needs to know that the collection has an enumerator, that the enumerator has a MoveNext method and a Current property, and that they have to repeatedly call MoveNext until it returns false. This information should be hidden from the programmer. Requiring the internal implementation details of the collection to be directly used defeats the purpose of having collection classes, when the reason for having them is to abstract the internal details of an enumerable collection class from the programmer.

Look at the equivalent C++/CLI code:
for each(String^ s in arraylist)
{
Console::WriteLine(s);
}
By adding constructs such as for each, which give developers a more natural syntax to access .NET features, the VC++ team has given us a cozy feeling that C++/ CLI is now a first-class language for .NET programming. Later in this chapter, you’ll see that boxing is now implicit, which means you don’t have to use the gratuitous __box keyword required in the old syntax. If you don’t know what boxing means, don’t worry; it will be explained when we talk about boxing and unboxing.

Poor integration of C++ and .NET
One major complaint about Managed C++ was that C++ features such as templates and deterministic destruction weren’t available. Most C++ developers felt severely handicapped by the apparent feature reductions when using MC++.

With C++/CLI, templates are supported on both managed and unmanaged types. In addition, C++/CLI is the only CLI language that supports stack semantics and deterministic destruction (although languages like C# 2.0 use indirect workarounds like the using-block construct to conjure up a form of deterministic destruction).

A crisp summarization would be to say that C++/CLI bridges the gap between C++ and .NET by bringing C++ features such as templates and deterministic destruction to .NET, and .NET features like properties, delegates, garbage collection, and generics to C++.

Confusing pointer usage
Managed C++ used the same * punctuator-based operator syntax for unmanaged pointers into the C++ heap and managed references into the CLI heap. Not only was this confusing and error-prone, but managed references were different entities with totally different behavioral patterns from unmanaged pointers. Consider the following code snippet:
__gc class R
{
};
class N
{
};

. . .
N* pN = new N();
R* pR = new R(); 
The two calls to new (shown in bold) do completely different things. The new call on the native class N results in the C++ new operator being called, whereas the new call on the managed class R is compiled into the MSIL newobj instruction. The native object is allocated on the C++ heap, but the managed object is allocated on the garbage-collected CLR heap, which has the side implication that the memory address for the object may change every time there is a garbage-collection cycle or a heap-compaction operation. The R* object looks like a native C++ pointer, but it doesn’t behave like one, and its address can’t be assumed to remain fixed. The good news is that this issue has been fixed in C++/CLI. We now have an additional gcnew keyword for instantiating managed objects. We also have the concept of a handle (as opposed to a pointer) to a managed object that uses the ^ punctuator (instead of *) as the handle operator. Later in this chapter, we’ll take a more detailed look at handles and the gcnew operator. For now, it should suffice to note that in C++/CLI, there will be no managed/unmanaged pointer confusion.

Unverifiable code
The Managed C++ compiler could not produce verifiable code, which meant that you couldn’t use it to write code that was to run under a protected environment— such as an SQL Server-stored procedure. Visual C++ 2005 supports a special compiler mode (/clr:safe) that produces verifiable code and disallows you from compiling any non-verifiable code by generating errors during compilation. The advantage of being able to create verifiable assemblies is that the CLR can enforce active CLR security restrictions on the running application. This gives you a wider scope to deploy your applications (for example, as SQL Server components) in secure environments like those in a banking system and in future Windows releases where code may have to be verifiable to be permitted to execute.

It should be obvious by now why Microsoft decided to bring out a new syntax. If you’ve never used the old syntax, you can consider yourself lucky that you can now use the powerful new C++/CLI language to write managed applications.

If you have used the old syntax, I strongly recommend spending some time porting the old syntax code to the new syntax as early as possible. The old syntax support (available in VC++ 2005 through the /clr:oldSyntax compiler switch) isn’t guaranteed to be available in future VC++ versions, nor will any significant improvements be made to it. Let’s now move on to our first C++/CLI program.


1.2 HELLO WORLD IN C++/CLI

Before we go any further, let’s write our first Hello World application in C++/CLI. In this section, we’ll also look at the new compiler options that have been introduced in VC++ 2005 to support compilation for managed code. There is nothing overly-complicated about the code in Listing 1.1, but for our purposes, it does nicely to illustrate a few basic language concepts of C++/CLI.

You can compile this code from the command line using the C++ compiler cl.exe as follows:
cl /clr First.cpp
Run it, and it promptly displays "Hello" followed by the current user (most likely your Windows login name) on the console. Except for the gcnew keyword (which we’ll talk about later in this chapter), it doesn’t look very different from a regular C++ program, does it? But the executable that has been created is a .NET executable that runs on the .NET Common Language Runtime. When I say .NET executable, I mean an MSIL program that is JIT compiled and executed by the CLR just like any executable you might create using C#, VB.NET, or another CLI language. This is a small example, but it communicates two important facts: You can use familiar C++ syntax to write .NET applications, thereby avoiding the need to learn a new language like C# or VB.NET; and you can write managed and native code within the same application.

For those of you who aren’t familiar with the .NET Framework, Console is a .NET Framework BCL class that belongs to the System namespace (hence the using namespace declaration on top), and WriteLine is a static method of the Console class. Listing 1.1 uses native data types like TCHAR and DWORD as well as managed data types like String. Similarly, it uses a native Win32 API call (GetUserName) as well as a managed class (System::Console). The best part is that you do all this in a single application (within a single function, in this case). Although you may not have realized it, you’ve just written a mixed-mode application that mixes native and managed code. Congratulations! You can do a lot with mixed-mode coding, and you’ll see far more useful applications of that technique throughout the later portions of this book.

You must have observed that I specified /clr as a compiler option. Let’s talk a little more about that.

1.2.1 The /clr compiler option

To use the C++/CLI language features, you need to enable the /clr compiler switch; without it, cl.exe behaves like a native C++ compiler. The /clr switch creates a .NET application that’s capable of consuming .NET libraries and can take advantage of CLR features such as managed types and garbage collection. You can specify suboptions to the /clr option to further specify the type of assembly you want created. Table 1.2 is a partial list of the /clr suboptions you can specify and what they do. For a more complete list, refer to the MSDN documentation for the C++ compiler command-line switches.

Now that we’ve discussed the command-line compiler options, let’s look at how you can use the VC++ 2005 environment to create C++/CLI projects.

1.2.2 Using VC++ 2005 to create a /clr application

For any nontrivial program, it makes sense to use the Visual C++ development environment, although it’s still good to know the compiler options available. I believe that one of the biggest reasons for the popularity of the VC++ compiler is the fact that it comes with a powerful development environment, and there’s no reason we shouldn’t take advantage of it. For the rest of this chapter and the next two chapters, we’ll use CLR-enabled console applications as we look at the C++/ CLI syntax and grammar. Those of you who want to follow along in your own console project can type in the code as it’s written in the book.

NOTE:
In later chapters, where the examples are longer and more complex, you can use the book’s companion CD, which contains full source code for the samples.

Creating a CLR console application with Visual C++ is straightforward. The steps are as follows.
  1. In the New Project Wizard dialog, choose CLR under Visual C++ in the Project types tree control on the left, and select CLR Console Application from the Templates list control on the right. You can use Figure 1.2 as a reference when doing this.


  2. Enter a name for the project, and click OK.
The wizard generates quite a few files for you. The one that should interest you most is the CPP file that has the same name as the project. If you named your project Chapter01Demo, you’ll see a Chapter01Demo.cpp file in your solution that contains the wizard-generated main method. You must have used similar wizards in the past when working on MFC, ATL, or Win32 API projects, so this should be familiar.

You’ll notice something interesting about the way the generated main function is prototyped:
int main(array<System::String ^> ^args)
This version of main is compatible with the entry-point prototypes available for C# and VB.NET programs and adheres to the CLI definition of a managed entrypoint function. The syntax may seem a little confusing right now (because we haven’t yet begun exploring the C++/CLI syntax), but args is essentially a managed array of System::String objects that represents the command-line arguments passed to the application. Keep this important distinction in mind: Unlike the native C++ main prototypes, the name of the program isn’t passed as the zero-indexed argument. If you run the application without any command-line arguments, the array will be empty. By default, the wizard sets the project to use the /clr compilation option, but you can change that by using the Project Properties dialog; you can access it by choosing Project > Properties or by using the Alt-F7 keyboard shortcut.

NOTE:
Your keyboard shortcuts will vary depending on your VS profile. This book uses the shortcuts associated with the default VC++ profile.

Select General from Configuration Properties on the left, and you’ll see an option to set the /clr compilation switch (you can choose from /clr, /clr:pure, /clr:safe, and /clr:oldSyntax), as shown in Figure 1.3. Now that you’ve seen how to create a C++/CLI project, let’s look at the typedeclaration syntax for declaring CLI types (also referred to as CLR types). When you learn how to declare and use CLR types, you get a proper feel for programming on top of the CLR.


1.3 DECLARING CLR TYPES

In this section, we’ll look at the syntax for declaring CLI (or CLR) types, modifiers that can be applied to CLI types, and how CLI types implement inheritance. C++/CLI supports both native (unmanaged) and managed types and uses a consistent syntax for declaring various types. Native types are declared and used just as they are in standard C++. Declaring a CLI type is similar to declaring a native type, except that an adjective is prefixed to the class declaration that indicates the type being declared. Table 1.3 shows examples of CLI type declarations for various types.

C# developers may be a little confused by the usage of both class and struct for both reference and value types. In C++/CLI, struct and class can be used interchangeably (just as in standard C++), and they follow standard C++ visibility rules for structs and classes. In a class, methods are private by default; in a struct, methods are public by default. In Table 1.3, RefClass1::Func and ValClass1::Func are both private, whereas RefClass2::Func and ValClass2::Func are both public. For the sake of clarity and consistency with C#, you may want to exclusively use ref class for ref types and value struct for value types instead of mixing class and struct for both ref and value types.

Interface methods are always public; declaring an interface as a struct is equivalent to declaring it as a class. This means IType1::Func and IType2::Func are both public in the generated MSIL. C# developers must keep the following in mind:
  • A C++/CLI value class (or value struct) is the same as a C# struct.
  • A C++/CLI ref class (or ref struct) is the same as a C# class.
Those of you who have worked on the old MC++ syntax should remember these three points:
  • A ref class is the same as an __gc class.
  • A value class is the same as an __value class.
  • An interface class is the same as an __interface.
Spaced keywords

An interesting thing that you need to be aware of is that only three new, reserved keywords have been introduced in C++/CLI: gcnew, nullptr, and generic. All the other seemingly new keywords are spaced (or contextual) keywords. Syntactic phrases like ref class, for each, and value class are spaced keywords that are treated as single tokens in the compiler’s lexical analyzer. The big advantage is that any existing code that uses these new keywords (like ref or each) continues to compile correctly, because it’s not legal in C++ to use a space in an identifier. The following code is perfectly valid in C++/CLI:
int ref = 0;
int value = ref;
bool each = value == ref;
Of course, if your existing code uses gcnew, nullptr, or generic as an identifier, C++/CLI won’t compile it, and you’ll have to rename those identifiers.

You’ve seen how CLI types can be declared. Next, you’ll see how type modifiers can be applied to these classes (or structs, as the case may be).

1.3.1 Class modifiers

You can specify the abstract and sealed modifiers on classes; a class can be marked both abstract and sealed. But such classes can’t be derived explicitly from any base class and can only contain static members. Because global functions aren’t CLS-compliant, you should use abstract sealed classes with static functions, instead of global functions, if you want your code to be CLS-compliant.

In case you’re wondering when and why you would need to use these modifiers, remember that, to effectively write code targeting the .NET Framework, you should be able to implement every supported CLI paradigm. The CLI explicitly supports abstract classes, sealed classes, and classes that are both abstract and sealed. If the CLI supports it, you should be able to do so, too.

Just as with standard C++, an abstract class can only be used as a base class for other classes. It isn’t required that the class contains abstract methods for it to be declared as an abstract class, which gives you extra flexibility when designing your class hierarchy. The following class is abstract because it’s declared abstract, although it doesn’t contain any abstract methods:
ref class R2 abstract
{
public:
    virtual void Func(){}
};
An interesting compiler behavior is that if you have a class with an abstract method that isn’t marked abstract, such as the following class, the compiler issues warning C4570 (class is not explicitly declared as abstract but has abstract functions) instead of issuing an error:
ref class R1
{
public:
    virtual void Func() abstract;
};
In the generated IL, the class R1 is marked abstract, which means that if you try to instantiate the class, you’ll get a compiler error (and you should). Not marking a class abstract when it has abstract methods is untidy, and I strongly encourage you to explicitly mark classes abstract if at least one of their methods is abstract. Note how I’ve used the abstract modifier on a class method in the previous example; you’ll see more on this and other function modifiers in chapter 2.

Using the sealed modifier follows a similar syntax. A sealed class can’t be used as a base class for any other class—it seals the class from further derivation:
ref class S sealed
{
};

ref class D : S // This won't compile
{               // Error C3246
};
Sealed classes are typically used when you don’t want the characteristics of a specific class to be modified (through a derived class), because you want to ensure that all instances of that class behave in a fixed manner. Because a derived class can be used anywhere the base class can be used, if you allow your class to be inherited from, by using instances of the derived class where the base class instance is expected, users of your code can alter the expected functionality (which you want to remain unchangeable) of the class. For example, consider a banking application that has a CreditCardInfo class that is used to fetch information about an account holder’s credit-card transactions. Because instances of this class will be occasionally transmitted across the Internet, all internal data is securely stored using a strong encryption algorithm. By allowing the class to be inherited from, there is the risk of an injudicious programmer forgetting to properly follow the data encryption implemented by the CreditCardInfo class; thus any instance of the derived class is inherently insecure. By marking the CreditCardInfo class as sealed, such a contingency can be easily avoided.

A performance benefit of using a sealed class is that, because the compiler knows a sealed class can’t have any derived classes, it can statically resolve virtual member invocations on a sealed class instance using nonvirtual invocations. For example, assuming that the CreditCardInfo class overrides the GetHashCode method (which it inherits from Object), when you call GetHashCode at runtime, the CLR doesn’t have to figure out which function to call. This is the case because it doesn’t have to determine the polymorphic type of the class (because a Credit- CardInfo object can only be a CreditCardInfo object, it can’t be an object of a derived type—there are no derived types). It directly calls the GetHashCode method defined by the CreditCardInfo class.

Look at the following example of an abstract sealed class:
ref class SA abstract sealed
{
public:
       static void DoStuff(){}
private:
       static int bNumber = 0;
};
As mentioned earlier, abstract sealed classes can’t have instance methods; attempting to include them will throw compiler error C4693. This isn’t puzzling when you consider that an instance method on an abstract sealed class would be worthless, because you can never have an instance of such a class. An abstract sealed class can’t be explicitly derived from a base class, although it implicitly derives from System::Object. For those of you who’ve used C#, it may be interesting to know that an abstract sealed class is the same as a C# static class.

Now that we’ve discussed how to declare CLI types and apply modifiers on them, let’s look at how CLI types work with inheritance.

1.3.2 CLI types and inheritance

Inheritance rules are similar to those in standard C++, but there are differences, and it’s important to realize what they are when using C++/CLI. The good thing is that most of the differences are obvious and natural ones dictated by the nature of the CLI. Consequently, you won’t find it particularly strenuous to remember them.

Reference types (ref class/struct) only support public inheritance, and if you skip the access keyword, public inheritance is assumed:
ref class Base
{
};

ref class Derived : Base // implicitly public
{
};
If you attempt to use private or protected inheritance, you’ll get compiler error C3628. The same rule applies when you implement an interface; interfaces must be implemented using public inheritance, and if you skip the access keyword, public is assumed:
interface class IBase
{
};

ref class Derived1 : private IBase {}; //error C3141
ref class Derived2 : protected IBase {}; //error C3141
ref class Derived3 : IBase {}; //public assumed
The rules for value types and inheritance are slightly different from those for ref types. A value type can only implement interfaces; it can’t inherit from another value or ref type. That’s because value types are implicitly derived from System::ValueType. Because CLI types don’t support multiple base classes, value types can’t have any other base class. In addition, value types are always sealed and can’t be used as base classes. In the following code snippet, only the Derived3 class compiles. The other two classes attempt to inherit from a ref class and a value class, neither of which is permitted:
ref class RefBase {};
value class ValBase {};
interface class IBase {};

value class Derived1 : RefBase {}; //error C3830
value class Derived2 : ValBase {}; //error C3830
value class Derived3 : IBase {};
These restrictions are placed on value types because value types are intended to be simple types without the complexities of inheritance or referential identity, which can be implemented using basic copy-by-value semantics. Also note that these restrictions are imposed by the CLI and not by the C++ compiler. The C++ compiler merely complies with the CLI rules for value types. As a developer, you need to keep these restrictions in mind when designing your types. Value types are kept simple to allow the CLR to optimize them at runtime where they’re treated like simple plain old data (POD) types like an int or a char, thus making them extremely efficient compared to reference types.

Here’s a simple rule you can follow when you want to decide whether a class should be a value type: Try to determine if you want it to be treated as a class or as plain data. If you want it to be treated as a class, don’t make it a value type; but if you want it to behave just as an int or a char would, chances are good that your best option is to declare it as a value type. Typically, you’ll want it to be treated as a class if you expect it to support virtual methods, user-defined constructors, and other aspects characteristic of a complex data type. On the other hand, if it’s just a class or a struct with some data members that are themselves value types, such as an int or char, you may want to make that a value type.

One important point to be aware of is that CLI types don’t support multiple inheritance. So, although a CLI type can implement any number of interfaces, it can have only one immediate parent type; if none is specified, this is implicitly assumed to be System::Object.

Next, we’ll talk about one of the most important features that have been introduced in VC++ 2005: the concept of handles.



Page: 1, 2

next page



ADS BY GOOGLE SPONSORED LINKS FEATURED LINKS

WinConnections Conference Fall 2008
Don’t miss the premier event for Microsoft IT Professionals in Las Vegas, November 10-13. Register and book your room by August 25 and receive a FREE room night (based on a three night minimum stay).

Maximize your SharePoint Investment – 8 Cities
Discover best practices and tips for both architecting and administering SharePoint. Early Bird Price of $99 through Sept 15th.

Find a new job now on the all new IT Job Hound!
Search jobs, post your resume, and set up job e-mail alerts!

Master SharePoint with 3 eLearning Seminars
Learn how to build a better SharePoint infrastructure and enable powerful collaboration with MVPs Dan Holme and Michael Noel. Register today!

Top Tools for Virtualization Disaster Recovery & Replication
View this web seminar on August 14th to learn about two tools that will result in faster backup and restore with P2V disaster recovery.

SharePointConnections Conference Fall 2008
Don’t miss the premier event for Microsoft IT Professionals in Las Vegas, November 10-13. Register and book your room by August 25 and receive a FREE room night (based on a three night minimum stay).

VMworld 2008 - Sign Up Today!
Join your peers on September 15-18 at The Venetian Hotel in Las Vegas as VMware hosts VMworld 2008, the leading Virtualization event.



When managing just VMware isn’t enough
Plan/Manage/Secure – NetIQ VMware management. Download whitepaper.

What’s up with your network? Find out with ipMonitor
Availability monitoring for servers, applications and networks – FREE trial

Microsoft® Tech•Ed EMEA 2008 IT Professionals
Advance your thinking with new ideas and practical real-world solutions at Microsoft’s FIVE day technical infrastructure conference 3-7 Nov., 2008. Register before 26 September 2008 to save €300.

Order Your Fundamentals CD Today!
Gain an introduction to Exchange, learn server security requirements, and understand how unified communications can play a role in your messaging strategies with this free Exchange CD.

Are You Really Compliant with Software Regulations?
View this web seminar that will help you with compliance best practices and check out a management solution to assure that you won’t be in jeopardy of an audit.

Virtualization Congress Oct. 14-16 in London
Don't miss Virtualization Congress, the premiere EMEA conference dedicated to hardware, OS and application virtualization. Oct. 14-16 in London.
Windows IT Pro Home Register FAQ for Windows WinInfo News
Europe Edition About Us Contact Us/Customer Service Media Kit Affiliates / Licensing  
SQL Server Magazine Office & SharePoint Pro Windows Dev Pro IT Job Hound ITTV
IT Library Technical Resources Directory Connected Home Windows Excavator Windows SuperSite 
 
 Windows IT Pro is a Division of Penton Media Inc.
 Copyright © 2008 Penton Media, Inc., All rights reserved. Terms and Use | Privacy Statement | Reprints and Licensing