< C++ .NET Value Type 4 | Main | C++ .NET Operator Overloading 2 >


 

 

C++ .NET Operator Overloading 1

 

 

What we have in this page?

 

  1. Introduction

  2. What Is Operator Overloading?

  3. What Types Need Overloaded Operators?

  4. What Can You Overload?

  5. Rules of Overloading

  6. Overloading Operators in Managed Types

  7. Overloading Value Types

  8. Overloading Arithmetic Operators

--------------Next---------------------------

  1. Operator Overloading in Unmanaged C++

  2. Overloading Operator Functions

  3. Implementing Logical Operators and Equality

  4. What Is Equality?

  5. Implementing Equals

  6. Implementing Assignment

  7. Implementing Increment and Decrement

  8. Overloading Reference Types

  9. Implementing Overloaded Operators for Reference Types

  10. Calling Overloaded Operators for Reference Types

  11. Guidelines for Providing Overloaded Operators

  12. The CLS methods

  13. Decimal.op_Addition Method

  14. Decimal.op_Decrement Method

  15. Decimal.op_Division Method

  16. Decimal.op_Equality Method

  17. Decimal.op_GreaterThan Method

  18. Decimal.Parse Method (String, IFormatProvider)

  19. Quick Reference For This Module

 

 

Introduction

 

You’ve already seen how to construct classes and structs, provide member functions in your types, and use these functions in programs. In this module, you’re going to find out about a special category of member functions called overloaded operator functions, which allow you to add extra functionality so that your types can be used more naturally and intuitively. If you’ve met operator overloading in C++ before, you need to be aware that overloading is handled completely differently in managed C++ than in traditional C++ though the syntax-wise may be similar. In fact, managed C++ types aren’t allowed to implement traditional C++ overloaded operators, so you’ll need to pay close attention to this module to find out how operator overloading is now done.

 

What Is Operator Overloading?

 

You already met the operators provided by the C++ language before. The problem is that those operators work only with the built-in types, and you’re starting to use classes and structs to define your own data types. This means that if you want to do an addition operation or a comparison operation on types that you’ve created, you can’t use the + and == operators because the compiler doesn’t know how to apply them to your types. Operator overloading is a C++ feature that lets you define operators to work with your types, that is a user defined type which can often lead to a more natural style of programming, so instead of writing this:

object3 = object1.Add(object2);

you can write this:

object3 = object1 + object2;

What Types Need Overloaded Operators?

 

In general, overloaded operators are needed by classes that wrap simple values. Types can be split into three broad classifications, as shown in the following table.

 

Classification

Defining Characteristics

Examples

Values

Values wrap data; if two objects contain the same data, those objects are identical.

String, Matrix, Date, and Time

Services

Services have little or no state data. They provide services through their member functions.

CreditCardCheck and AddressLookup

Entities

Entities have an identity that is unique for each object.

BankAccount (identified by account number) and Person (identified by Social Security number)

 

Table 1

 

Values are the classes for which you’ll most often find yourself implementing overloaded operators. You can imagine wanting to implement +, >, ==, and other operators for types such as Date and String, but it’s harder to see when you might want them for the other classifications. Service types, which have little or no state, don’t tend to need operators: what would comparing two AddressLookup objects mean? Entity types might have some operators, but their meaning might not be intuitive. You could use == to check two BankAccounts for equality, but what would that mean? There’s more on equality later on in this module; let’s move on to see how operator overloading works.

 

What Can You Overload?

 

You learned about the rich set of operators that C++ supports. You can overload many of these, but there are some restrictions. Traditional C++ won’t let you overload several of the more esoteric operators, such as sizeof() and the member-of dot operator. Managed C++ extends the list and adds a number of other C++ operators that can’t be overloaded, including ->, (), and []. The main reason for this restriction is that the Common Language Specification (CLS) is designed for use across languages, and as such, it will support a set of operators that are useful to all .NET languages, rather than support C++-specific operators. You’ll see later exactly which operators .NET lets you overload.

 

Rules of Overloading

 

Several rules apply when overloading operators. The problem is that you can implement operators to mean whatever you like, so some rules are needed to impose some limits and to prevent giving the compiler an impossible job.

  1. You cannot define any new operators. Even if you think that %% would make a neat new operator, you can’t add it.

  2. You can’t change the number of operands taken by an operator. You might think it would be really useful to create a unary / operator, but the division operator always has to have two operands.

  3. You can’t change the precedence or associativity of operators. So, * will always take precedence over +, regardless of what they are actually implemented to mean for a type, and (for example) the left operand of a * will always be evaluated before the right operand.

Overloading Operators in Managed Types

 

Overloading operators in managed types is quite different from how you overload them in traditional C++. The CLS defines the list of arithmetic, logical, and bitwise operators that .NET languages can support, and compiler vendors use the language’s native operators to implement these functions. So, when you override an operator in a managed C++ type, you don’t override the C++ operator, but instead, you override the underlying CLS functionality. If you’re currently a C++ programmer, be aware that the compiler won’t let you implement normal C++ operator overloads in managed types. You have to use the overloading mechanism that we’ll describe.

 

Overloading Value Types

 

Let’s start by adding operator overloading to value types and then move on to reference types. You already know that value types are the types most likely to need operator overloading.

 

Overloading Arithmetic Operators

 

In this exercise, you will see how to implement operators in a value type. The exercise also introduces many of the techniques you’ll need to use when adding operator overloading to your own types.

 

1.        Start Microsoft Visual C++/Studio .NET, and create a new CLR Console Application project named Overload.

 

Creating a new CLR Console Application project named Overload

 

2.        At the top of the Overload.cpp file, immediately under the using namespace System; line, add the following struct definition:

// The Dbl struct definition

value struct Dbl

{

   double val;

   public:

      Dbl(double v) { val = v; }

      double getVal() { return val; }

};

Adding a struture definition to the main program file

 

This simple Dbl struct is the one you’ll use throughout these exercises. It simply wraps a double and then provides a constructor for creating and initializing Dbl objects and a get function for accessing the data member. As you might remember from previous modules, the keyword value makes Dbl a .NET value type rather than a traditional C++ struct.

 

3.        Create or instantiate three Dbl objects in your main() function.

Dbl d1(10.0);

Dbl d2(20.0);

Dbl d3(0.0);

4.        Add a call to Console::WriteLine to print out the value of d3:

Console::Write("Value of d3 is ");

Console::WriteLine(d3.getVal());

Remember that you have to use the dot operator to reference members of a managed object.

 

5.        Try adding d1 and d2 and assigning the result to d3. Insert this line into your code immediately before the call to Console::Write:

d3 = d1 + d2;

Adding objects using the overloaded + operator

 

6.        Build your project. When you try this, you’ll find that it doesn’t work; the compiler gives you a C2676 error.

1>------ Build started: Project: Overload, Configuration: Debug Win32 ------

1>Compiling...

1>stdafx.cpp

1>Compiling...

1>AssemblyInfo.cpp

1>Overload.cpp

1>.\Overload.cpp(22) : error C2676: binary '+' : 'Dbl' does not define this operator or a conversion to a type acceptable to the predefined operator

1>Generating Code...

1>Build log was saved at "file://f:\vc2005project\Overload\Overload\Debug\BuildLog.htm"

1>Overload - 1 error(s), 0 warning(s)

========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

The compiler is telling you that it doesn’t have a + operator to use that works with Dbl objects, so it can’t perform the operation.

 

7.        Implement the + operator for the struct by adding the following code to the struct definition, immediately after the getVal function:

static Dbl operator+(Dbl lhs, Dbl rhs)

{

    Dbl result(lhs.val + rhs.val);

    return result;

}

 

Redefining the + operator so that it can add objects - overload the + operator

 

Let’s analyze this function. The keyword static, tells you that this function belongs to the Dbl struct as a whole, rather than to any one instance of the struct. The addition operation is implemented by the operator+ function, which is one of the overloadable functions defined in the new C++. The operator keyword declares a function specifying what operator-symbol means when applied to instances of a class. This gives the operator more than one meaning, or "overloads" it. The compiler distinguishes between the different meanings of an operator by examining the types of its operands. The general syntax for operator overloading is:

type operator operator-symbol ( parameter-list )

The name of an overloaded operator is operatorx, where x is the operator that can be overloaded (refer to the list at the end of this module or column C++ Operator in the following Table). For example, to overload the addition operator, you define a function called operator+. Similarly, to overload the addition/assignment operator, +=, define a function called operator+=. The following table lists the most commonly used operators supported by the CLS, together with their C++ equivalents. So the use of the new C++ operator keyword for operator overloading reverts back to the traditional C++ when the CLS became a standard. The Managed Extension for C++ uses the CLS functions as shown in the following Table.

 

Operation

C++ Operator

CLS Functions/Methods

Decrement

--

op_Decrement

Increment

++

op_Increment

Unary minus

- (unary)

op_UnaryNegation

Unary plus

+ (unary)

op_UnaryPlus

Addition

+ (binary)

op_Addition

Subtraction

- (binary)

op_Subtraction

Multiplication

*

op_Multiply

Division

/

op_Division

Modulus

%

op_Modulus

Assignment

=

op_Assign

Equality

==

op_Equality

Inequality

!=

op_Inequality

Less than

<

op_LessThan

Less than or equal to

<=

op_LessThanOrEqual

Greater than

>

op_GreaterThan

Greater than or equal to

>=

op_GreaterThanOrEqual

Logical AND

&&

op_LogicalAnd

Logical OR

||

op_LogicalOr

Logical NOT

!

op_LogicalNot

Left-shift

<<

op_LeftShift

Right-shift

>>

op_RightShift

Bitwise AND

&

op_BitwiseAnd

Bitwise OR

|

op_BitwiseOr

Exclusive OR

^

op_ExclusiveOr

 

Table 2

 

To overload an operator, you pick the equivalent function from the list and implement it in your class. The arguments   a function takes and what it returns depend on the function. In this case, we’re implementing the binary addition operator, so the arguments are going to be two Dbl values, and the return type will also be a Dbl value. You can see how the function works. The result of adding two Dbl values has to be a third Dbl, so you create a third one, initialize it with the contents of the two operands, and return it.

 

 

 

 

Part 1 | Part 2 | Part 3 | Part 4 | Part 5 | Part 6 | Part 7

 


 

< C++ .NET Value Type 4 | Main | C++ .NET Operator Overloading 2 >