Programming: Week 3 (cont.)

Ex. 3

Write a TemperatureConverter class that handles conversions between Celsius, Fahrenheit and Kelvin. Each conversion mode should have its dedicated method; the user should be able to choose which conversion mode to use.

Here is the program:

#include 
#include 
#include 

class TemperatureConverter
{
public:
		void SetTemp(std::string input)//set methods - provide data entered by the user to the Class
		{
			int n = input.length();
			char sist = input.at(n - 1);
			float temp_part = std::stof(input.erase(n - 1, 1));
			temperature = temp_part;
		};
		void SetSource(std::string input)
		{
			int n = input.length();
			char sist = input.at(n - 1);
			source = sist;
		};
		void SetTarget(char convert_to)
		{
			target = convert_to;
		};
		float GetTemp()//Get methods - provide data in member variables to other methods in the Class
		{
			return temperature;
		};

		char GetSource()
		{
			return source;
		};
		char GetTarget()
		{
			return target;
		};
		float C2K()//Convert methods - convert temperature values from one scale to another
		{
			return GetTemp() + 273.15f;
		};
		float K2C()
		{
			return GetTemp() - 273.15f;
		};
		float K2F()
		{
			return 9 * GetTemp() / 5 - 459.67f;
		};
		float F2K()
		{
			return 5 * GetTemp() / 9 + 255.37f;
		};
		float F2C()
		{
			return 5 * (GetTemp() - 32) / 9;
		};
		float C2F()
		{
			return 9 * GetTemp() / 5 + 32;
		};
		void Convert()//determine which conversion method to run and call PrintResult() method
		{
			if (GetTarget() == GetSource())
				std::cout << "Target scale same as source scale!" << std::endl;
			else switch (GetTarget())
				{
					case 'C':
					{	
						if (GetSource() == 'F') PrintResult(F2C());
						else PrintResult(K2C());
						break;
					};
					case 'F':
					{	
						if (GetSource() == 'C') PrintResult(C2F());
						else PrintResult(K2F());
						break;
					};
					case 'K':
					{	
						if (GetSource() == 'F') PrintResult(F2K());
						else PrintResult(C2K());
						break;
					};
					default:
						std::cout << "Wrong input!" << std::endl;
						break;
				};
		};
		void PrintResult(float converted)//output the converted value to the user
		{
			std::cout << GetTemp() << " " << GetSource() << " is " << converted << " " << GetTarget() << std::endl;
		};
private:
		float temperature;
		char source;
		char target;
};

void main(){
	TemperatureConverter temperature;
	std::string entered_temp;
	char to_scale = '0';
	std::cout << "*******************************************************" << std::endl;
	std::cout << "***             TEMPERATURE CONVERTER               ***" << std::endl;
	std::cout << "*******************************************************" << "nn";
	std::cout << "Allowed temperature conversions:n" << std::endl;
	std::cout << "(C) to Celsius" << std::endl;
	std::cout << "(F) to Fahrenheit" << std::endl;
	std::cout << "(K) to Kelvin" << std::endl;
	std::cout << "nEnter a temperature followed by a degrees symbol, e.g.,n-16.45C for -16.45 degrees Celsius.n" << std::endl;
	std::getline(std::cin, entered_temp);
	while (entered_temp.at(0) != 'q')
	{
		temperature.SetTemp(entered_temp);
		temperature.SetSource(entered_temp);
		std::cout << "nChoose scale to convert to, e.g. enter K to convert to Kelvin." <> to_scale;
		temperature.SetTarget(to_scale);
		temperature.Convert();
		std::cout << std::endl << "nEnter another temperature or 'q' to quit." << std::endl;
		std::cin.ignore();
		std::getline(std::cin, entered_temp);
	}
}

main() Function

The main() function compared to the class definition is pretty small. What it does is instantiate an object of the class (so that the class can be used at all), define variables entered_temp and to_scale, which will be used to accept user input, and call methods to process user data.

The program asks the user to input a string ending in C, F or K. This makes the program aware which scale the initial temperature is in. The program then asks for one more input, which scale to convert to – again, C, F or K is expected.

Both inputs are passed to the set-methods of the class. Then Convert() method is called (described later) which takes care of the conversion.

The statements that read user input, pass it to the class and call Convert() are enclosed in a do-loop. This makes sure the user can repeat temperature conversion with different values in one run.

The variable entered_temp also contains the signal the user wants to enter quit program. The loop is stopped when the user enters the ‘q’ character which is read into the entered_temp string (that will be the only character in the string, thus the .at(0) method).

Class Structure

Within the class, three private member variables are declared (lines 96-98): temperature to contain the temperature that is to be converted; source to contain the scale we are converting from; target to contain which scale we are converting to.

The three set-methods, SetTemp(), SetSource() and SetTarget(), are called directly from main() and set the private member variables to the values passed by the main() function.

The three get-methods, GetTemp(), GetSource() and GetTarget() allow other class members access the member variables indirectly.

Each of the six convert-methods, C2F(), C2K(), F2C(), F2K(), K2C() and K2F() call the GetTemp() method to get the temperature entered by the user and using the value calculate the temperature in the new scale and return the value.

Once the value is known, it is passed to the PrintResult(), method which prints out the sentence stating which conversion was made and what the result was. To do so, this method calls all of the three get-methods since it needs to know what was the original temperature the user entered and what the target scale was. The very result is fed into the PrintResult() method as a parameter.

Convert() method is what decides which conversion is to be made. It calls GetTarget() and GetSource() methods and compares their returns to find out which conversion the user wants. Then PrintResult() method is called with appropriate conversion method passed to it as the parameter. Convert() also checks if the user did not ask to convert to the same scale that the temperature was input in. If that’s the case, Convert() prints a message and exits to main().

String Opeartions

When doing these exercises, I often need to manipulate strings. Here are some useful string methods (a string is not a fundamental data type but a class in C++!) to manipulate them:

string.length() – returns an int which specifies the size of the string (i.e., how many characters it contains)

string.at(i) – returns the (i+1)-th element (a char) of the string. Recall that the very first element of an array (and a string) has the index 0!

string.erase(i,n) – returns a string which is obtained by removing n characters starting with position number i in the original string. So e.g.,

std::string test = "abcde";
test.erase(2,2);
std::cout << test;

will print out abe because deletion begins at position 2 (third element which is “c”) and goes on until 2 elements in a row are deleted (i.e., “cd”, which leaves us with “abe”).

std::stof(string) – returns a float obtained by casting the string to a float. Non numerical characters will be ignored

Final Comments

If the user follows instructions and does not enter wrong data the program works as designed. I did not include data validation because that’s too much time-consuming and not the point of this exercise. Also, you can understand how the original temperature entered by the user, e.g., 50C is interpreted by the program. Function main() passes this string to the set-methods of the class; one of them copies of the last character of the string and stores is as source (the original scale) while the other removes the last character from the string, converts the string to float and stores the float as temperature (the value in the original scale).

Ex. 4

Below is a code fragment that declares a class:

class Time{
public:
	Time(int hour, int minute, int second);
	unsigned int GetSecondsSinceMidnight();
private:
	unsigned int m_hours;
	unsigned int m_minutes;
	unsigned int m_seconds;
};

Finish defining the class. Implement the methods. Make sure parameters are validated.

Here is the program:

#include 
#include 
#include  // to format how integers are output with std::cout <<

class Time
{
public:
	Time(int hour, int minute, int second)//This is the constructor of the class!
	{
		SetTime(hour,minute,second);
	};
	void SetTime(int hour, int minute, int second)
	{
		m_hours = hour;
		m_minutes = minute;
		m_seconds = second;
	};
	unsigned int GetSecondsSinceMidnight()
	{
		return 3600 * m_hours + 60 * m_minutes + m_seconds;
	};
private:
	unsigned int m_hours;
	unsigned int m_minutes;
	unsigned int m_seconds;
};

int main()
{
	unsigned int hh, mm, ss;
	bool cont = true;
	while (cont)
	{
		std::cout <> hh;
		std::cout <> mm;
		std::cout <> ss;
		if (hh > 23 || mm > 59 || ss > 59)
		{
			std::cout << "One or more data is wrong!n";
			continue;
		};
		std::cout << std::setfill('0') << "Current time is " << std::setw(2) << hh << ":" << std::setw(2) << mm << ":" << std::setw(2) << ss << std::endl;
		Time time(hh, mm, ss);
		std::cout << "Number of seconds elapsed since midnight: " << time.GetSecondsSinceMidnight() << std::endl;
		std::cout <> cont;
	}
	return 0;
}

Since the first method in the class has the same name as the class itself, we must assume that is the class’s constructor. It takes three arguments which it must receive from the main(). Constructor itself should not modify member variables but instead call the set-method of the class.

GetSecondsSinceMidnight() method is pretty self-explanatory, it accesses the member variables, calculates the result and returns it.

The main() function collects user input and validates it. I chose to move validation out of the class as having it inside would mean constructor or the set-method should validate it. But then, should any of them fail, object instantiation in line 46 should fail, then what?

Validation itself checks if the number of hours, minutes and seconds does not exceed 23, 59 and 59, respectively. Since the variables hh, mm and ss are declared as unsigned int, we do not need to check if they are positive, so only the upper bound has to be validated.

To make sure the values are output in the usual electronic clock format, i.e., 00:00:00, I need to format the integers being output. For that, I include library and use the functions std::setfill('0') to set the padding character to 0 and std::setw(2) to make sure each string is output with at least two significant digits. So as a result should the user enter mm = 2, the result will become

00:02:00

and not

00:2:00.

About Rokas Paulauskas

2014  Programming