Why Don't I Get Those Keywords?

Do you ever get jealous when you're reading code in other managed languages? Code that uses keywords such as Property and Delegate and using. Have you ever wondered whether you could use those in your C++ applications? You can, but it's not always obvious how to do so. In this column, I'll show you two such keywords and the Managed C++ equivalents.

Property

Public Class Person

    Public Sub New(ByVal newname As String)
        pName = newname
    End Sub
    Private pName As System.String
    Public Property Name() As String
        Get
            Return pName
        End Get
        Set(ByVal Value As String)
            pName = Value
        End Set
    End Property

    Public Sub Report()
        Console.WriteLine("My name is " & Me.Name)
    End Sub

End Class

Being able to hide away the "get" and the "set" behind that property keyword gives code that uses your class the best of both worlds: It looks as though they're just talking to a public variable, but you could be enforcing some business rules on a set, or storing a completely different variable than what is passed to or returned from the property. For example, it makes sense to have a property called Age but not to store anyone's age, which changes every day. Instead, you can store the birthdate and calculate the age on request, or update the birthdate if the age has changed. Yet, to consumers of your code, it feels very much as though Age is a public variable.

When you write a Managed C++ application, you can use either the properties or the hidden get and set methods, whichever you prefer. Intellisense shows them all:

I prefer to use the property directly:

int _tmain()
{
    Contacts::Person* p = new Contacts::Person("Kate");
    p->Name = "Kate Gregory";
    p->Report();
    return 0;
}

Using properties from C++ code is just as easy as using them from VB code, so could defining them be easy, too? Sure it could. The only catch is that you can only define properties like this on a managed type (class or struct).

Here's an example:

__gc class Building
{
private:
    int sqft;
public:
    Building(): sqft(0) {}
    Building(int squarefeet): sqft(squarefeet) {}
    __property int get_squarefeet()
    {
        return sqft;
    }
    __property void set_squarefeet(int value)
    {
        sqft = value;
    }
};

You could be forgiven for finding this less than intuitive syntax: You put the __property keyword on the get and set functions independently, rather than on some surrounding element. (How do you remember the names to use? Check that Intellisense screenshot again for the properties defined in VB.NET.) The functions could be miles apart in a large header file, which would confuse a developer. Exercise a little discipline and keep them close together. And you do get some checking: The compiler insists that the parameter type for the set and the return type for the get match, for example. Expect to see an improvement in this syntax in a future version of Visual C++. For now, awkward or not, it works. Here's some C++ code using the property:

    Building* b = new Building(100);
    Console::WriteLine("Building is {0} square feet",
                       __box(b->squarefeet));

Because I like to think of Managed C++ as the ultimate interop language, the support for .NET properties is important to me. I expect to write assemblies and class libraries in C++ that will be called from many other languages, languages that aren't as interop-capable. And I don't want developers in those other languages to have to call my GetSquareFeet() and SetSquareFeet() functions, thus reminding them that my code is different and exotic somehow. I want it to feel normal and comfortable, and to slide right into their project as some sort of shim over to the unmanaged world. Using properties is a good way to achieve that feel. It's also more convenient even in my own C++ code: doing away with extra typing while keeping all the benefits of encapsulation.

Delegates

A delegate, we like to say when presenting to C- and C++-aware audiences, is like a typesafe function pointer. Here's a trivial VB example:

Delegate Function Compare(ByVal x As String, _
           ByVal y As String) As Boolean

Function CompareValues(ByVal X As String, _
             ByVal Y As String) As Boolean
   If X > Y Then
       CompareValues = True
   Else
       CompareValues = False
   End If
End Function

The reason it's typesafe is that the delegate signature and the signature of a function that will use it must match, and the compiler will help to ensure that all works out, without the flurry of brackets and stars that seem to be involved doing function pointers in traditional C++. By the way, although it's not obvious from the code snippet, CompareValues() is a member function of a VB.NET class. Here's some code that uses it in another member function of the same class:

Dim c As Compare = AddressOf CompareValues
Dim result As Boolean = c("Kate", Me.Name)
If result Then
   Console.WriteLine("Kate is greater than " & Me.Name)
Else
   Console.WriteLine("Kate is not greater than " & Me.Name)
End If

In addition to the delegate keyword, this snippet also uses the AddressOf keyword in VB.NET. It's probably not a surprise that there's no new __ keyword for that in Managed C++. After c has been assigned to the address of CompareValues, code that appears to call c() actually calls CompareValues().

Of course, this delegate example is utterly trivial, here so you can see the syntax. Delegates are vital for event handling, asynchronous callbacks, and hooking into framework-provided classes such as collections. A more realistic example would pass c as a parameter to some function (perhaps something that sorts collections) that needs to know how to compare two particular items (two Person objects, perhaps.) That function can be written very generally and will work with the delegate you pass in, invoking your function as though the name was generally known.

If you want to use that sort of functionality from C++, you're going to need to know how to make a delegate from a function. Alternatively, you may want to provide that functionality from C++ and use a delegate that calling code hands to you.

Here's an addition to the Building class that knows how to compare two buildings. You could use an operator overload here if you preferred:

bool CompareValues(Building* b1, Building* b2)
{
    if (b1->sqft > b2->sqft)
        return true;
    else 
        return false;
}

(Like the rest of the Building class, this is declared inline in the header file.)

Delegates can't just be declared in the middle of a function, the way you might say "int i;" in passing. They must either be member variables of a managed class or globals. This C++ code declares a delegate before main, then uses it:

__delegate bool Compare(Building* b1, Building* b2);
int _tmain()
{
//...
    Building* b = new Building(5000);
    Building* cottage = new Building(1000);

    Compare* c = new Compare(b, &Building::CompareValues);
    bool result = c(b,cottage);
    if (result)
        Console::WriteLine("b is greater than cottage");
    else
        Console::WriteLine("b is not greater than cottage");
//...

As you can see, you actually construct a C++ delegate by passing two parameters to the constructor: The first is the instance on which you want to call the member function, and the second is the address of the member function. That's a little more awkward than the VB equivalent, but at least it's not impossible: If there's some framework code you want to use that takes a delegate, this is how to get one to it.

To use the delegate, it's just as simple as the VB.NET way: Invoke it as though the delegate name were itself a function, and pass the parameters to it. As with the earlier example, this would only be truly useful if the code that set the delegate and the code that used the delegate were in different methods, free from knowing about each other.

More?

A lot of people still believe that Managed C++ can't do certain things that VB.NET and C# can do. Can't is much too strong a word. Some things are much harder in Managed C++ because there's no RAD designer to generate code for you—VSTO applications, for example. Most things are exactly the same: same framework libraries, same runtime, same COM Interop and P/Invoke capabilities. Some things are a little more awkward, typically involving double underscores and some twisted syntax, but at least they're still possible. They let your C++ code play everywhere the equivalent VB.NET and C# code would play. And, never forget that C++ has abilities those languages do not: the ability to generate unmanaged code, to call unmanaged code that is not a COM component or a DLL, to use multiple inheritance, templates, and other features not supported by the CLR when you really can't do without them.

The limitations that people perceive for C++ are generally just that—perceptions. So, why not try using the C++ equivalents of features such as properties and delegates that you've seen in samples for other languages? Let me know how they work for you.

About the Author

Kate Gregory is a founding partner of Gregory Consulting Limited (www.gregcons.com). In January 2002, she was appointed MSDN Regional Director for Toronto, Canada. Her experience with C++ stretches back to before Visual C++ existed. She is a well-known speaker and lecturer at colleges and Microsoft events on subjects such as .NET, Visual Studio, XML, UML, C++, Java, and the Internet. Kate and her colleagues at Gregory Consulting specialize in combining software develoment with Web site development to create active sites. They build quality custom and off-the-shelf software components for Web pages and other applications. Kate is the author of numerous books for Que, including Special Edition Using Visual C++ .NET.




Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

  • Java developers know that testing code changes can be a huge pain, and waiting for an application to redeploy after a code fix can take an eternity. Wouldn't it be great if you could see your code changes immediately, fine-tune, debug, explore and deploy code without waiting for ages? In this white paper, find out how that's possible with a Java plugin that drastically changes the way you develop, test and run Java applications. Discover the advantages of this plugin, and the changes you can expect to see …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds