Main

Lab 5

Objectives

Practice C++ parameter passing, operator overloading (documentation), default arguments (documentation), strings (documentation)

C++ function parameter passing

In this part of the lab, we will demonstrate how passing arguments by reference works in C++ (remember that C does not support passing by reference, only passing by value).

(Make sure you have first read: Introduction to C++ References in TICPP ch. 3.)

1. Write three different functions in C++ (no class needed, but you can put them in a class if you wish) whose prototypes are shown below. Inside each function, increment the values of x and y. Write a main program that calls each function and prints out the values of the arguments after each call.

void increment1(int x, int y);
void increment2(int &x, int &y);
void increment3(int *x, int *y);

Now try changing increment2 to void increment2(const int &x, const int &y);. The compiler should now produce a syntax error.

Using const is good for several reasons:

  • It enlists the compilers help in ensuring values that shouldn’t be changed aren’t changed.
  • It tells the coder whether they need to worry about the function changing the value of the argument
  • It helps debugging

Rule: Always pass by const reference unless you need to change the value of the argument

Advantages of passing by reference:

  • The function can change the value of the argument, which is sometimes useful.
  • Because a copy of the argument is not made, this is fast, even when used with large structs or classes.
  • We can pass by const reference to prevent unintentional changes.
  • A function can modify multiple values.

Disadvantages of passing by reference:

  • Because a non-const reference can not be made to a literal or an expression, reference arguments must be normal variables (e.g., you cannot do increment2(2,3) or increment2(1+4, 4-2);).
  • It can be hard to tell whether a parameter passed by reference is meant to be input, output, or both.
  • It’s impossible to tell from the function call that the argument may change. An argument passed by value and passed by reference looks the same. We can only tell whether an argument is passed by value or reference by looking at the function declaration. This can lead to situations where the programmer does not realize a function will change the value of the argument.
  • Because references are typically implemented by C++ using pointers, and dereferencing a pointer is slower than accessing it directly, accessing values passed by reference is slower than accessing values passed by value.

C++ Operator Overloading

In this part of the lab, we will practice overloading operators in C++.

1. Write a Pizza class which has a container data member for toppings (you decide which, e.g., set or vector). You can have other relevant data members. Make sure all data members are private. To save time since lab time is limited, you can put the class declaration, implementation, and main in the same file, e.g., pizza.cpp (normally this is not a good design choice). As you add each new feature to your class, make sure to test it by using it in your main().

2. Write the following two public constructors: 1) a default constructor (no arguments) and 2) a constructor which accepts a vector<string> of toppings as initial values (see documentation for vectors). Examples of instantiating pizzas:

Pizza p1;  // default pizza (you decide on default toppings)
Pizza p2(....toppings_vector....); // pepperoni pizza

Hint: to create a vector from several strings, use the vector constructor that takes an array as an argument, e.g., string a[] = {"abc","def"}; vector<string> v(a,a + sizeof(a) / sizeof(string));

Choose appropriate data member values for the default (no argument) constructor; for example, cheese and marinara as the toppings, perhaps a crust type, or anything else you would like on your default pizza. If you've never had a pizza, do some research at the Pizza Hut or Dominos websites or ask a knowledgeable friend for suggestions. In both of the constructors, print a (fun) message to standard out, indicating which constructor was called and the number of toppings.

If you allocate any of your data members with new in the constructor, implement a destructor function ~Pizza() with delete calls.

4.Overload the std::ostream& operator<< in the Pizza class to produce a description of the pizza. Here is an example of how you can use this in your main():

  Pizza p; // default pizza
  cout << p << endl;

If you wish, you can optionally implement a simple getString function to serialize the pizza object into a string, and then use that in your overloaded << operator. Don't forget to make the overloaded operator function a friend (see documentation).

5. Overload the + operator for Pizza to allow toppings to be added. You may wish to create several overloaded versions that accept different arguments, e.g., a string, an array of strings, or a vector of strings.

Green Marinee theme adapted by David Gilbert, powered by PmWiki