FUNCTION PARAMETERS
- The following sections address a couple of C++ best practices relating to the use of function parameters.
- This includes when you should use pointers instead of references to pass objects into a function and when you should use default arguments.
Pointer versus Reference Parameters
bool GetColor(int r, int g, int b); // pass by valuebool GetColor(int &r, int &g, int &b); // pass by reference
bool GetColor(int *r, int *g, int *b); // pass by pointer
- Pass a parameter as a reference or pointer when you want to receive a handle for the actual object rather than a copy of the object. This is done either for performance reasons or so that you can modify the client’s object.
- C++ compilers normally implement references using pointers so they are often the same thing under the hood.
- A reference must be initialized to point to an object and does not support changing the referent object after initialization.
- You cannot take the address of a reference as you can with pointers. Using the & operator on a reference returns the address of the referent object.
- You can’t create arrays of references.
- prefer the use of references over pointers for any input parameters. This is because the calling syntax for your clients is simpler and you do not need to worry about checking for NULL values
object.GetColor(&red, &green, &blue); // pass by pointer
- In both of these cases, the GetColor() function can modify the value of the red, green, and blue variables. However, the pointer version makes this fact explicit due to the required use of the & operator.
- For this reason, APIs like the Qt framework prefer to represent output parameters using pointers instead of references.
- Recommend reference parameters should be const references.
- For input parameters prefer the use of const references over pointers where feasible.
- For output parameters, consider using pointers over non-const references because it indicates explicitly to the client that they may be modified
Default Arguments
- Default arguments are a very useful tool to reduce the number of methods in your API and to provide implicit documentation on their use.
- They can also be used to extend an API call in a backward-compatible fashion so that older client code will still compile, but newer code can optionally provide additional arguments (although it should be noted that this will break binary compatibility, as the mangled symbol name for the method will necessarily change
class Circle
{
public:
Circle(double = 0, double = 0, double radius =10.0);
};
- Above class supports combinations of arguments that don’t make logical sense but will compile, not a good approach
class Circle
{
public:
Circle();
Circle(double x, double y);
Circle(double x, double y, double radius);
};
- Above class, multiple overloaded constructors have been provided and default values are declared in the implementation CPP file, not the header file, this is good practice
- As a result, a later version of the API could change these values without any impact on the public interface.
- Prefer overloaded functions to default arguments when the default value would expose an implementation constant.
- As a performance note, you should also try to avoid defining default arguments that involve constructing a temporary object because these will be passed into the method by value and can therefore be expensive.
References
- API Design for C++ Book by Martin Reddy
No comments:
Post a Comment