What s Different in the Revised Language Definition?

Support for Operator Overloading

 

 

Perhaps the most baffling aspect of the original language design is its support for operator overloading or rather, its effective absence. As an outsider, I took it as evidence of an abandonment, and felt this absolutely required fixing if Microsoft was really serious in its commitment to C++. Well, the good news is that the support for operator overloading has been fixed (bringing with it all those things implicit in its support). Although it can be shrugged off as just syntax, I have always felt it to be a litmus test of a revised language design yes, more so even than finalistic determination.

 

Within the declaration of a reference type, for example, rather than using the native operator+ syntax, one had to explicitly write out the underlying internal name of the operator in this case, op_Addition. More onerous, however, is the fact that the invocation of an operator had to be explicitly invoked through that name, thus precluding the two primary benefits of operator overloading: (a) the intuitive syntax, and (b) the ability to intermix new types with existing types. For example,

public __gc __sealed class Vector

{

public:

     Vector( double x, double y, double z );

      

     static bool    op_Equality( const Vector*, const Vector* );

     static Vector* op_Division( const Vector*, double );

     static Vector* op_Addition( const Vector*, const Vector* );

     static Vector* op_Subtraction( const Vector*, const Vector* );

};

 

int main()

{

       Vector *pa = new Vector( 0.231, 2.4745, 0.023 );

       Vector *pb = new Vector( 1.475, 4.8916, -1.23 );

 

       Vector *pc1 = Vector::op_Addition( pa, pb );

       Vector *pc2 = Vector::op_Subtraction( pa, pc1 );

       Vector *pc3 = Vector::op_Division( pc1, pc2->x() );

 

       if ( Vector::op_Equality( pc1, p2 ))

            // &

}

In the language revision, the usual conventions are restored. Nothing really surprising here one could almost call the change boring, but in this case, that is a good thing. Well, the only surprising thing, which is an aspect of the underlying CLR, is the absence of a static subscript operator, which is factored out into what in C++/CLI is referred to as an indexed property. But this is a good thing as well, but that is for another entry.

public ref class Vector sealed

{

public:

       Vector( double x, double y, double z );

 

       static bool    operator ==( const Vector^, const Vector^ );

       static Vector^ operator /( const Vector^, double );

       static Vector^ operator +( const Vector^, const Vector^ );

       static Vector^ operator -( const Vector^, const Vector^ );

};

 

int main()

{

       Vector^ pa = gcnew Vector( 0.231, 2.4745, 0.023 ),

       Vector^ pb = gcnew Vector( 1.475,4.8916,-1.23 );

 

       Vector^ pc1 = pa + pb;

       Vector^ pc2 = pa pc1;

       Vector^ pc3 = pc1 / pc2->x();

 

       if ( pc1 == p2 )

            // &

}

The purpose of this series of blog entries is to document the changes between the original and revised language design (I should probably just designate these as Thing1 (T1) and Thing2 (T2) and be done with it) rather than address the many new and innovative language features (such as the support for non-static operators within a managed class). For that, I recommend you check out (a) the blogs of Herb Sutter and Brandon Bray or (b) download the C++/CLI Candidate Base Document [sorry, I don t have the URL handy], or (c) both of the above. However, I would like to break that rule in one small case.

 

One of the petty annoyances of .NET is its lack of support for default arguments. For example, a Vector class would like to support four varieties of object initialization, as follows:

 

int main()

{

       Vector^ p1 = gcnew Vector;

       Vector^ p2 = gcnew Vector( 1.475 );

       Vector^ p3 = gcnew Vector( p2[ 0 ], 2.4745 );

       Vector^ p4 = gcnew Vector( p3[ 1 ], p2[ 0 ], 3.14159 );

}

 

In native C++, one could do that with a single constructor with a default argument of zero for each coordinate parameter. Under the constraint of .NET, one must provide four separate constructors, the signature of each mapping to the successive constructor invocations in the above example. C# provides support for a delegating constructor, which relieves the programmer from having to implement all four instances. Rather, one delegates values to one implementing constructor. T2 has added this to its feature list:

 

public ref class Vector sealed

{

       double m_x, m_y, m_z;

public:

       Vector() : Vector( 0.0, 0.0, 0.0 ){}

Vector( double x ) : Vector( x, 0.0, 0.0 ){}

Vector( double x, double y ) : Vector( x, y, 0.0 ){}

       Vector( double x, double y, double z ) : m_x( x ), m_y( y ), m_z( z ){}

 

       // &

};

 

disclaimer: This posting is provided "AS IS" with no warranties, and confers no rights.