Know When And How To Add Operators To Your Classes So They Behave Like Built-In Types And Let You Write Code That Just Makes Sense
You know about the types built into the C++ language now. Take the simple int type for example. You can create a variable of this type, give it the value 1, and then add two in order to get the value 3. All this is so natural that it’s easy to read and understand the code. If your variable is called speed, then your code would look like this:
int speed = 1;
speed += 2;
You also know that C++ lets you create your own types. There’s no way that the language and library designers could ever predict all the types that all the programmers in the world will be creating.
Imagine if C++ stopped here. You can create a new class to manage the speed of a robot, for example. But you won’t be able to do something as simple as add the value 2. Instead, you’ll have to write a method. Maybe you call the method goFaster. It kinda reads okay. Your code could have a variable of the RobotSpeed type called robotSpeed with an initial value of 1. And you could write this to add 2:
But you look at that and think how much better it would be if instead you could write code that looked and behaved just like an int. What you really want is something like this:
RobotSpeed robotSpeed = 1;
robotSpeed += 2;
With C++, you don’t have to settle for the first solution that doesn’t quite seem right. Sure, the language doesn’t know anything about robot speed controllers. But you do. At least you should if you’re writing code to manage robots.
You get to tell the C++ language all about your new robot speed controller including how to get it to behave just like all the built-in types. Your code looks just like the int type shown earlier.
There’s a lot of operators available to you and all but a few of them are open for you to redefine so they know exactly how to work with your custom types. This is one of the biggest and most powerful abilities of C++ because it lets you write code that blends in with the language so it all seems natural.
The class is divided into three parts.
Part one starts with an overview of the operators and introduces you to terms that you’ll need to understand.
- associativity will be described later
Boolean operations will introduce you to logic. Truth tables show the results of input combinations.
- and (&&) or (and)
- or (||) or (or)
- exclusive or (no operator for this)
- not (!) or (not)
Relational operations let you make decisions and test for conditions. This is how your code will know when it’s had enough, or when the game is over, or when it still needs to keep working on something.
- less than (<)
- less than or equal (<=)
- greater than (>)
- greater than or equal (>=)
- equal (==)
- not equal (!=) or (not_eq)
Math operators are what you might expect from operators. The C++ language doesn’t treat these as anything special.
- increment (++), prefix and postfix
- decrement (–), prefix and postfix
- plus (+), both unary and binary
- minus (-), both unary and binary
- multiplication (*)
- division (/)
- modulo (%)
Part two starts here with bitwise operations and masking and shifting.
- and (&) or (bitand)
- or (|) or (bitor)
- exclusive or (^) or (xor)
- not (~) or (compl)
- shift left (<<)
- shift right (>>)
Assignment and assignment together with operators are how you change variables. Without these, your code would never be able to remember anything.
- simple assignment (=)
- assignment plus (+=)
- assignment minus (-=)
- assignment multiply (*=)
- assignment divide (/=)
- assignment modulo (%=)
- assignment and (&=) or (and_eq)
- assignment or (|=) or (or_eq)
- assignment xor (^=) or (xor_eq)
- assignment left shift (<<=)
- assignment right shift (>>=)
Conditional operation is the only operator that takes three parts. It takes a little getting used to and will let you write less code.
- conditional (?:)
Comma operation is interesting because it doesn’t do much. But what it does is sometimes exactly what you need.
- comma (,)
Casting operations let you change between types.
- functional cast (type ())
- type conversion ((type))
- Better casting
- Signed vs. unsigned comparison
- Narrowing conversion
- Casting to integers and doubles during calculation
Part three starts with access operations and wraps up by describing how all the operators work together.
- subscript ()
- dereference pointer (*)
- address-of (&)
- indirect member selection (->)
- direct member selection (.)
Function call operations are what let you call methods. This operator can also let you make classes callable.
- function call (())
Order of operations and precedence can get complicated at times. Especially if you rely completely on the defined operator precedence. A little extra parenthesis can sometimes make your code more readable even if they might not be absolutely necessary.
- Grouping and scope operations let you specify exactly what you want.
- parenthesis (())
- scope (::)
- Associativity controls how operators relate to the rest of the expression.