Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com
Answertopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

Thinking in C++
Prev Contents / Index Next

Arguments & return values

It may seem a little confusing at first when you look at OverloadingUnaryOperators.cpp, Integer.h and Byte.h and see all the different ways that arguments are passed and returned. Although you can pass and return arguments any way you want to, the choices in these examples were not selected at random. They follow a logical pattern, the same one you’ll want to use in most of your choices.

  1. As with any function argument, if you only need to read from the argument and not change it, default to passing it as a const reference. Ordinary arithmetic operations (like + and , etc.) and Booleans will not change their arguments, so pass by const reference is predominantly what you’ll use. When the function is a class member, this translates to making it a const member function. Only with the operator-assignments (like +=) and the operator=, which change the left-hand argument, is the left argument not a constant, but it’s still passed in as an address because it will be changed.
  2. The type of return value you should select depends on the expected meaning of the operator. (Again, you can do anything you want with the arguments and return values.) If the effect of the operator is to produce a new value, you will need to generate a new object as the return value. For example, Integer::operator+ must produce an Integer object that is the sum of the operands. This object is returned by value as a const, so the result cannot be modified as an lvalue.
  3. All the assignment operators modify the lvalue. To allow the result of the assignment to be used in chained expressions, like a=b=c, it’s expected that you will return a reference to that same lvalue that was just modified. But should this reference be a const or nonconst? Although you read a=b=c from left to right, the compiler parses it from right to left, so you’re not forced to return a nonconst to support assignment chaining. However, people do sometimes expect to be able to perform an operation on the thing that was just assigned to, such as (a=b).func( ); to call func( ) on a after assigning b to it. Thus, the return value for all of the assignment operators should be a nonconst reference to the lvalue.
  4. For the logical operators, everyone expects to get at worst an int back, and at best a bool. (Libraries developed before most compilers supported C++’s built-in bool will use int or an equivalent typedef.)

The increment and decrement operators present a dilemma because of the pre- and postfix versions. Both versions change the object and so cannot treat the object as a const. The prefix version returns the value of the object after it was changed, so you expect to get back the object that was changed. Thus, with prefix you can just return *this as a reference. The postfix version is supposed to return the value before the value is changed, so you’re forced to create a separate object to represent that value and return it. So with postfix you must return by value if you want to preserve the expected meaning. (Note that you’ll sometimes find the increment and decrement operators returning an int or bool to indicate, for example, whether an object designed to move through a list is at the end of that list.) Now the question is: Should these be returned as const or nonconst? If you allow the object to be modified and someone writes (++a).func( ), func( ) will be operating on a itself, but with (a++).func( ), func( ) operates on the temporary object returned by the postfix operator++. Temporary objects are automatically const, so this would be flagged by the compiler, but for consistency’s sake it may make more sense to make them both const, as was done here. Or you may choose to make the prefix version non-const and the postfix const. Because of the variety of meanings you may want to give the increment and decrement operators, they will need to be considered on a case-by-case basis.

Thinking in C++
Prev Contents / Index Next

 
 
   Reproduced courtesy of Bruce Eckel, MindView, Inc. Design by Interspire