Introduction
I managed to grab Nick Hodapp, Microsoft's Visual C++ .NET Product Manager, during PDC 2003 to get the skinny on what the future holds for C++ devs in .NET 2.0. Since the release of .NET support for writing managed code in C++ has been via managed extensions. Many developers have found these extensions complicated, a little messy, and, to be brutal, not that much fun. Microsoft have listened to developers and reworked the way C++ and the CLI work together. The final result addresses many of the initial concerns and provides a syntax that is at home in native development as it is in managed code.
What are the main changes in Visual C++ .NET for Whidbey?
In nutshell, the next version of Visual C++ .NET is about evolving the managed extensions into something that is far more useable for the C++ developer. We're bringing C++ to .NET and bringing .NET to C++. Something we probably missed the mark on in the first iteration. We had lots of feedback from developers saying managed extensions aren't useable for the scenarios most people are interested in. The scenarios we banked on were interop scenarios. Now that people are thinking about Longhorn, they are wondering how they are going to get there from C++. This is where Whidbey comes in.
What are the main features being introduced in Whidbey?
In order to being C++ and .NET together we had to add new features so there was more of an impedance match [between .NET and C++]. October 1 saw the announcement of the C++/CLI standard with ECMA. Whidbey is Microsoft's implementation of that standard.
The main features added in Whidbey include [Code samples taken from Herb Sutter's talk Visual C++ “Whidbey”: New Language Design And Enhancements given at PDC 2003]
- The
^
syntax has been introduced to represent a managed handle to an object on the managed heap. The syntax for a handle is analogous to pointer syntax:. T^ t = gcnew T;
The reference handle %
has also been introduced as the managed equivalent to &
. The CLR handles all problems associated with a reference handle moving around as the garbage collector moves memory. The type of %R
is R^.<BR><BR>
- Properties have been added, including trivial properties in which the compiler creates the get/set functions. The new Property syntax is not dependant on the CLR but can be used for both managed and unmanaged code.
ref class R {
int mySize;
public:
property int Size {
int get() { return mySize; }
void set( int val ) { mySize = val; }
}
};
R r;
r.Size = 42;
ref class R {
public:
property int Size; };
- Default indexed properties have also been added
ref class R {
map<STRING^,INT>* m;
public:
property int Lookup[ String^ s ] {
int get() { return (*m)[s]; }
protected:
void set( int ); }
property String^ default[ int i ] { }
};
void R::Lookup[ String^ s ]::set( int v ) { (*m)[s] = v; }
...
R r;
r.Lookup["Adams"] = 42; String^ s = r[42];
- MFC programs can make use of Windows Forms more easily
- You can now override functions that do not necessarily have the same name as the overriding function.
interface class I1 { int f(); int g(); };
interface class I2 { int f(); int h(); };
interface class I3 { int h(); int i(); };
ref class R : I1, I2, I3 {
public:
virtual int ff() override; virtual int f() sealed; virtual int x() = I1::g; virtual int y1() = I2::h; virtual int z() = i, I3::h; virtual int a() abstract; virtual int i() new; };
- Added the
sealed
and abstract
keywords. These have the same effect as the corresponding keywords in C#.
- Pointers have been cleaned up. Pointers always point to fixed locations in memory and the developer has the responsibility to clean up allocated memory. Pointers can also use pointer arithmetic.
Widget* s1 = new Widget; Widget^ s2 = gcnew Widget; s1->Length(); s2->Length();
(*s1).Length(); (*s2).Length();
- Native objects can be placed on the managed heap and garbage collected. Proxies are automatically created by compiler to handle the plumbing.
NativeType^ hNative = gcnew NativeType; RefType* pRef = new RefType;
- Boxing has been cleaned up and essentially automated. Implicit boxing means the syntax is clean and now allows .NET agnostic templates to be written (ie the same template will work for both managed and unmanaged types). There is, however, a very slight performance cost.
template<class T>
void swap( T% t1, T% t2 )
{ T tmp( t1 ); t1 = t2; t2 = tmp; }
This works for any copyable T, assuming copy construction/assignment are defined.
Object ^o1, ^o2; swap( o1, o2 ); int ^i1, ^i2; swap( i1, i2 ); swap( *i1, *i2 ); MessageQueue *q1, *q2; swap( q1, q2 ); swap( *q1, *q2 ); ref class R { } r1, r2; swap( r1, r2 ); value class V { } v1, v2; swap( v1, v2 ); class Native { } n1, n2; swap( n1, n2 );
- Strongly typed boxing has been added. This means boxing a native type will return a reference to that type, not a generic object
int^ i = 42; Object^ o = i; Console::WriteLine( "Two numbers: {0} {1}", i, 101 );
- C++ managed classes can now have destructors, meaning C++ now has deterministic finalisation. The destructor implicitly implements the Dispose pattern of managed code and includes chaining, and is called when a stack-based object goes out of scope, a class member's enclosing object is destroyed or when
delete
is called. Having destructors means that the classic stack based pattern can be used, which means less try/catch/finally blocks and cleaner code.
Object^ o = f();
delete o;
void DoStuff()
{
MyObject worker();
worker.DoSomething();
}
void DoStuff()
{
using ( MyObject worker() = new MyObject() )
{
worker.DoSomething();
}
}
}
- Every type can have a destructor, and every type can have a finalizer. The new finalizer syntax for the class
T
is !T()
.
- Generics have been included. Generics do not replace templates, they complement them. Generics are CLR based and templates are compiler/syntax based.
generic<typename T> where T : IDisposable, IFoo
ref class GR { void f() {
T t;
t.Foo();
} };
template< template<class> class V > void f() { V<int> v; }
f<GR>();
- STL now works nicely on the CLR. A .NET version of STL will be available that is fully verifiable.
stdcli::vector<STRING^> v;
for_each( v.begin(), v.end(), functor );
for_each( v.begin(), v.end(), _1 += "suffix" ); for_each( v.begin(), v.end(), cout << _1 ); g( %v ); for each (String^ s in v) Console::WriteLine( s );
- C++ works with WinFX
- Unified Type System
Also, all __
keywords have been removed (deprecated) so the syntax itself is far neater than previous. Unfortunately the PDC bits you received don't have all the features being presented so you will have to wait for the beta due out next year.
What would you say is the most useful feature addition in Whidbey?
Every C++ developer uses advanced features such as templates and deterministic finalisation - controlling the lifetime of an object using new and delete, or by allocating on the stack. To date there hasn't been a way to do this in C++ or even C#/VB.NET. Whidbey gives this back to C++ developers by giving them back the destructor.
Can you use C++ in ASP.NET?
The problems we experienced in Everett (see Semicolon - Finding bugs the hard way) have been cleaned up so yes - but it's not a supported scenario. C++ isn't your Web productivity language, it's your power and control language and so we feel C++'s role is to be used in creating components that ASP.NET pages will call. Some of the features available in C++ are overkill if you're only writing web logic.
What are some examples of bringing C++ to .NET and vice versa
Deterministic finalization, and taking all the ISO C++ features and enabling them for managed code are great examples of how we have brought C++ into .NET. There are also features in the CLR such as properties and events that have been added to C++. This is what C++/CLI is all about -making sure C++ features work in .NET and then extend C++ to take advantage of the CLR.
Chris Maunder is the co-founder of
CodeProject, DeveloperMedia and ContentLab, and has been a prominent figure in the software development community for nearly 30 years. Hailing from Australia, Chris has a background in Mathematics, Astrophysics, Environmental Engineering and Defence Research. His programming endeavours span everything from FORTRAN on Super Computers, C++/MFC on Windows, through to to high-load .NET web applications and Python AI applications on everything from macOS to a Raspberry Pi. Chris is a full-stack developer who is as comfortable with SQL as he is with CSS.
In the late 1990s, he and his business partner David Cunningham recognized the need for a platform that would facilitate knowledge-sharing among developers, leading to the establishment of CodeProject.com in 1999. Chris's expertise in programming and his passion for fostering a collaborative environment have played a pivotal role in the success of CodeProject.com. Over the years, the website has grown into a vibrant community where programmers worldwide can connect, exchange ideas, and find solutions to coding challenges. Chris is a prolific contributor to the developer community through his articles and tutorials, and his latest passion project,
CodeProject.AI.
In addition to his work with CodeProject.com, Chris co-founded ContentLab and DeveloperMedia, two projects focussed on helping companies make their Software Projects a success. While at CodeProject, Chris' roles included Architecture and coding, Product Development, Content Creation, Community Growth, Client Satisfaction and Systems Automation, and many, many sales meetings. All while keeping his sense of humour.