// Listing 14.5 Using function pointers

/*
pointers to functions eliminate duplicate code, make programs easier to read, 
and allow you to make tables of functions to call based on runtime conditions
*/

#include <iostream>
using namespace std;

void square(int &, int &);
void cube(int &, int &);
void swap(int &, int &);
void getVals(int &, int &);
void printVals(int, int);

int main()
{
	void (* pFunc) (int &, int &) = getVals;	// pFunc is a pointer to a function that accepts two integers passed by address and that returns a void. pFunc is initialized to the getVals function.
	bool fQuit = false;
	int valOne = 1;
	int valTwo = 2;
	int choice = 0;

	while (!fQuit)
	{
		cout << "(0)quit (1)change values (2)square (3)cube (4)swap: ";
		cin >> choice;

		switch (choice)
		{
		case 1: 
			pFunc = getVals; 
			break;
		case 2: 
			pFunc = square; 
			break;
		case 3: 
			pFunc = cube; 
			break;
		case 4: 
			pFunc = swap; 
			break;
		default: 
			fQuit = true; 
			break;
		}

		if (fQuit)
		{
			break;
		}

		printVals(valOne, valTwo);
		pFunc(valOne, valTwo);		// or (*pFunc)(valOne, valTwo);
		printVals(valOne, valTwo);
	}

	return 0;
}// end of main

void printVals(int x, int y)
{
	cout << "x: " << x << " y: " << y << endl;
}

void square (int & rX, int & rY)
{
	rX *= rX;
	rY *= rY;
}

void cube (int & rX, int & rY)
{
	int tmp;
	tmp = rX;
	rX *= rX;
	rX = rX * tmp;
	tmp = rY;
	rY *= rY;
	rY = rY * tmp;
}

void swap(int & rX, int & rY)
{
	int temp;
	temp = rX;
	rX = rY;
	rY = temp;
}

void getVals (int & rValOne, int & rValTwo)
{
	cout << "New value for ValOne: ";
	cin >> rValOne;
	cout << "New value for ValTwo: ";
	cin >> rValTwo;
}
