You met the operators provided by the C++ language in Chapter 3. 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, 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;
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.
Values wrap data; if two objects contain the same data, those objects are identical.
String, Matrix, Date, and Time
Services have little or no state data. They provide services through their member functions.
CreditCardCheck and AddressLookup
Entities have an identity that is unique for each object.
BankAccount (identified by account number) and Person (identified by Social Security number)
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 chapter; let’s move on to see how operator overloading works.
You learned about the rich set of operators that C++ supports in Chapter 3. 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.
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.
You cannot define any new operators. Even if you think that %% would make a neat new operator, you can’t add it.
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.
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.