;) Hello ladies and gents,

Ive written this class time in wich I have to use operator+ to increase the hour with a certain amount of minutes like this:

time t0 (23, 59), t1; // t0 = 23.59
t1 = t1 + 120; // t1 = 1.59

Problem is, I can't get those 120 minutes into the operator+ :confused:

I know that the calculation part isn't correct yet, but I'll sort that out later, I first want to be able to get those 120 minutes into the class :!:
Please, do not give the solution as to how I should do the calculation, ONLY how I can get those 120 minutes into the class ;)

This is the program Ive written sofar,

class time
{
public:

	time (int uren = 0, int minuten = 0) : hours (uren), minutes (minuten) {}
	
	time operator+ (const time &a)
	{
		while (a.minutes > 0)
		{
			if (minutes >= 60)
			{
				minutes = a.minutes - 60;
				hours += 1;
			}
		else
			minutes +=minutes;
		}
		
		return (hours, minutes);
	}

	void print()const
	{
		cout<< "The time is now: " << hours << "Hr " << minutes << "." <<endl;
	}

private:
	int hours, minutes;
};

int main()
{
	time t0(23, 59), t1;

	t0.print();

	t1 = t0 + 120;
	t1.print();
	
	return 0;
}

Thanks for the assistance ;)

You may want to choose a different name other than time, but since you are adding minutes, wouldn't it be like this?

mytime operator+ (int min)

Why choose a different name :?:

When I change it the way you say, I get two error messages:

error C2143: syntax error : missing ';' before '+' :?:
error C2501: 'mytime' : missing storage-class or type specifiers :?:

Why choose a different name :?:

Because time is a standard function.

When I change it the way you say, I get two error messages:

error C2143: syntax error : missing ';' before '+' :?:
error C2501: 'mytime' : missing storage-class or type specifiers :?:

Yeah, if you change the class name, you have to change it everywhere. I needed to do so to get it to compile -- it wouldn't as time (but that's likely a compiler issue).

Oh, now I understand, almost got it working tough, even with the use of class time ;)

I'm using Visual C 6.0, wich one do you use?

Only have to figure out how to correctly add the minutes towards the hour, but I'm almost there, I'll show you when it's finished so you could comment on it and perhaps improve it :)

Ive got other questions aswell, but I'll ask them when I figured out the program.

Thanks for the help Dave :)

>I'm using Visual C 6.0, wich one do you use?

Borland 5.5, generally.

>Only have to figure out how to correctly add the minutes towards the hour

While minutes is greater than 59, increment hours and subtract 60 from minutes.

I GOT IT :D Wohooooo :cheesy:

#include <iostream>
#include <iomanip>

using namespace std;

class time
{
public:

	time (int uren = 0, int minuten = 0) : hours (uren), minutes (minuten) {}
	
	time operator+ (int min)
	{
		minutes += min;
		while (minutes >= 60)
		{
			minutes -= 60;
			hours += 1;
			if (hours >= 24) hours = 0;		
		}
		
		return *this;
	}

	void print()const
	{
	hours < 10 ? cout<<"The time is now: " << setw(2) << hours <<" Hr "<< minutes << "." <<endl: 
             cout<<"The time is now: " << setw(0) << hours <<" Hr "<< minutes << "." <<endl;
	}

private:
	int hours, minutes;
};

int main()
{
	time t0(23, 47), t1;

	t0.print();

	t1 = t0 + 59;
	t1.print();
	
	return 0;
}

Hi guys,

Hehe, Ive got a few questions, but the first one that I'm gonna ask is, what would you do different or what would you simplify in this exercise?

One thing to keep in mind is, in main you have to use this code:

time t0(23, 59), t1;         // t0 = 23 Hr 59.
t1 = t0 + 120;               // t1 =  1 Hr 59.

Rest of the questions will come later, thanks ;)

>what would you do different
I wouldn't waste my time performing the calculations manually:

#include <ctime>
#include <iomanip>
#include <iostream>

using namespace std;

class Time {
public:
  Time ( int hours = 0, int minutes = 0 )
  {
    time_t t = time ( 0 );
    data = *localtime ( &t );

    data.tm_hour = hours;
    data.tm_min = minutes;

    normalize();
  }

  Time operator+ ( int minutes )
  {
    data.tm_min += minutes;
    normalize();

    return *this;
  }

  friend ostream& operator<< ( ostream& out, const Time& t )
  {
    char save = out.fill ( '0' );

    out<< setw ( 2 ) << t.data.tm_hour <<':'
       << setw ( 2 ) << t.data.tm_min;
    out.fill ( save );

    return out;
  }
private:
  void normalize()
  {
    time_t t = mktime ( &data );
    data = *localtime ( &t );
  }
private:
  struct tm data;
};

int main()
{
  Time t0(23, 59), t1;

  cout<< t0 <<endl;
  t1 = t0 + 120;
  cout<< t1 <<endl;
}

Waw Narue, that's what you could call, changing the program :D

I'm a bit baffled :eek: and actually don't know wich question to ask first :?:

Well, here it goes:

1) > I wouldn't waste my time performing the calculations manually:
Is that why you are using the header file <ctime> ?

2) When I look at what I wrote and what you wrote, yours is much more complicated! So, what advantage has your version got over mine?
- Speed?
- Portability?
- ...

Questions about my program:

3) What is the difference in using *this and time(hours, minutes) in my program, because I switched these and both work perfectly in returning the values of hours and minutes :?:
- I know '*this' is a pointer, but pointer for/from what ?
- By using time(hours, minutes), is this related towards the constructor ?

4) Maybe a stupid question, but does it matter in wich order you write private and public in a class?

5) Could I write this piece shorter, not using your alternative?

hours < 10 ? cout<<"The time is now: " << setw(2) << hours <<" Hr "<< minutes << "." <<endl:  
cout<<"The time is now: " << setw(0) << hours <<" Hr "<< minutes << "." <<endl;

There are other questions about your code, but I'm gonna give it several test drives to see wether I'm able to understand what's happening in your code and will comeback on them.

Thanks for the alternative solution Narue :!:

>Is that why you are using the header file <ctime> ?
The standard library already defines date and time functions and types (inherited from C). The reside in the <ctime> header. The ones I used were the tm struct, time_t, localtime, and mktime.

>yours is much more complicated!
Only if you aren't familiar with date and time handling in the standard library. The complexity in your version comes from operator+, where you have a loop and a bunch of magic numbers. A reader would need to verify that your math is correct as well as the algorithm performing the math. In my version it's a simple matter of making sure that I passed all of the right types to mktime and localtime. So the complexity is only skin deep.

>what advantage has your version got over mine?
Portability because the standard library handles the nitty gritty stuff. Flexibility because while you would need to design, implement, and test new features (such as adding seconds) with extensive algorithmic changes, I would only need to make a few minor and easily checked modifications. And scalability because by adding features your code will grow by leaps and bounds, mine will grow by only a handful of lines even if a lot of new functionality is added.

>What is the difference in using *this and time(hours, minutes) in my program
The former makes a copy of itself and returns it, the latter creates a new object. It's a subtle difference, and both will generally work the same with this class.

>I know '*this' is a pointer, but pointer for/from what ?
this could be better called self. It's a pointer to the object that the member functions are called on behalf of. So if I'm an object of L33tCoder, then this points to me, and *this is me.

>By using time(hours, minutes), is this related towards the constructor ?
Yes, you're calling the constructor directly and returning the result. It's just the same as saying:

time temp ( hours, minutes );
return temp;

In theory at least. Your compiler is more likely to optimize away any temporary objects by returning the constructor directly rather than creating your own temporary object.:

return temp ( hours, minutes ); // More likely to be optimized

>does it matter in wich order you write private and public in a class?
It can, but you're not likely to encounter such a situation for quite a while. ;)

>Could I write this piece shorter, not using your alternative?

cout<<"The time is now: "<< setw(hours < 10 ? 2 : 0) << hours <<" Hr "<< minutes <<"."<<endl;

Would be a start.

Thanks for the answers Narue, Ive been debugging your example, but several parts are to complicated for me to understand.

I thinks this is because there are several subjects Ive either just scratched the surface from (pointers, structures) and others I never read anything about yet.

The syntax may be a little confusing as I was going for relatively concise code and didn't include error checks. ;) Dereferencing a pointer returned by a function that can return a null pointer to get an object for immediate assignment isn't exactly the smartest thing in the world.

Dereferencing a pointer returned by a function that can return a null pointer to get an object for immediate assignment isn't exactly the smartest thing in the world.

You know, saying what you said above or saying it in Chinees to me, would have the same result :cheesy:

I'm asking myself, what the h*ll did she just say ;)

>saying what you said above or saying it in Chinees to me, would have the same result
:cheesy: It basically means that this:

T obj = *function();

Is generally an unsafe practice. It should be:

T *p = function();
T obj;
if ( p != 0 )
  obj = *p;

> T *p = function();
This means, that your declaring an object as a pointer with a function as variable?

> T obj;
Declaration of an object in a class.

>if ( p != 0 )
obj = *p;

If the value of p is not equal to zero, ... then Ive lost you, you put the pointer into the object???

I'm just trying to break it apart so it's abit clearer to me :!:

>This means, that your declaring an object as a pointer with a function as variable?
Defining a pointer to T and initializing it with the return value of a function.

>Declaration of an object in a class.
T stands for a generic type, so it could be a class object or an object of built in type.

>If the value of p is not equal to zero
Also read as "if p is not a null pointer".

>you put the pointer into the object???
Assign the data that the pointer points to, to the object.

Hi guys,

Next exercise:

Write a class Fractions to work with Fractions, like this for example:

Fractions a(3, 8) , b(4, 5), c = a * b;

Wich should result into de fractions a, b en c: 3/8, 4/5 and 3/10 (= 3/8 * 4/5).

Clues: Start with the operator* and / and add the more difficult operators + and - afterwards. Use the Greatest Common Divider function wich was used in exercise 4.4 to simplify fractions. When adding and subtracting with fractions you have to make sure that the denominators are made equal for wich you can use GCD function aswell. The Smallest Common Multiplicator for the denominator x and y can be calculated with: SCM(x, y) = xy/ GCD(x, y)

What Ive got so far is the multiplier operator* wich is this:

class Fractions
{
public:
	Fractions ( short a = 0, short b = 0) : numerator (a), denominator (b){}
	
	Fractions operator* (Fractions d)
	{
		Fractions result;
		
		result.numerator = numerator * d.numerator;
		result.denominator = denominator * d.denominator;

		while (result.denominator % 2 == 0 && result.numerator % 2 == 0)
		{
			result.numerator /= 2;
			result.denominator /= 2;
		}

		return result;
	}

	void print()
	{
		cout<< numerator << "/" << denominator <<endl;
	}

private:
	short numerator, denominator;
};

int main()
{
	Fractions fract1 (3, 8), fract2 (4, 5), c;

	fract1.print();
	fract2.print();

	c = fract1 * fract2;

	c.print();

	return 0;
}

This works out the way it should, meaning that my results are 3/8, 4/5 and 3/10.

But I was wondering wether this part could be written shorter or better:

Fractions operator* (Fractions d)
	{
		Fractions result;
		
		result.numerator = numerator * d.numerator;
		result.denominator = denominator * d.denominator;

		while (result.denominator % 2 == 0 && result.numerator % 2 == 0)
		{
			result.numerator /= 2;
			result.denominator /= 2;
		}

		return result;
	}

I was also wondering wether it wouldn't be better to write a separate class function for this piece of code, so that I maybe could use it for the other operators aswell if this works out to be necessary?

For reducing the fraction, a separate function that finds the greatest common divisor would be a good idea. Then you should define an explicit reduce member function since it's an operation you'll use a lot. It would also be a good idea for operator* to be a non-member function since it doesn't have to be called on behalf of either operand. Then you could change your operator* to:

void Fraction::reduce()
{
  short div = gcd ( numerator, denominator );

  numerator /= div;
  denominator /= div;
}

Fraction operator* ( const Fraction& a, const Fraction& b )
{
  Fraction result;

  result.numerator = a.numerator * b.numerator;
  result.denominator = a.denominator * b.denominator;
  result.reduce();

  return result;
}

Hi Narue,

Thanks for the explanation, few questions tough before I go further with this exercise.

> It would also be a good idea for operator* to be a non-member function...
1) Do you mean that it would be best to write this function outside the class? Don't understand what you're trying to explain to me :-|

Fraction operator* ( const Fraction& a, const Fraction& b )

2) why do you make Fraction constant?
3) why do you make two arguments and make them references? I tought that the first (numerator (3), denominator(8)) goes to operator* and the second (numerator(4), denominator(5)) goes to the argument

Fraction d

as in my program, so, I tought there wasn't a second argument necessary?

4) So, the only thing I have to write the code for is the

gcd ( numerator, denominator );

function correct?

5) Also, when I change my code like you wrote

Fraction operator* (const Fraction& a, const Fraction& b)

I get an error saying that Ive got to many parameters, I'm sure it's got to do with this piece of code in main

c = fract1 * fract2;

It's mentioned in the exercise to write it this way in main!

>Do you mean that it would be best to write this function outside the class?
Yes. Instead of this:

class Fraction {
public:
  Fraction operator* ( const Fraction& rhs );
  ...
};

Fraction Fraction::operator* ( const Fraction& rhs )
{
  ...
}

You would do this:

class Fraction {
public:
  friend Fraction operator* ( const Fraction& lhs, const Fraction& rhs );
  ...
};

Fraction operator* ( const Fraction& lhs, const Fraction& rhs )
{
  ...
}

I forgot to mention making it a friend in my other post, sorry.

>2) why do you make Fraction constant?
Because you don't change any of the data members. By making the parameters const, you'll be warned if any changes made to the function try to make modifications. More importantly, you can pass constant objects to the function:

const Fraction a ( 2, 3 );
const Fraction b ( 5, 10 );
Fraction c = a * b;

>3) why do you make two arguments and make them references?
operator* can be either a member function with one argument, or a non-member function with two arguments. When it's a member function, the object that you call the function on acts as the left side operand and the argument acts as the right side operand. When it's a non-member function, the first argument is the left side operand and the second argument is the right side operand.

The reason I used a non-member function is because you should strive to keep your class interface as sparse as possible. Any operations that can be made non-member functions or non-member friends should be. If we were talking about operator*= then it would be a member function, but operator* doesn't need to be.

It's generally best to pass class objects by reference to avoid the overhead of calling the copy constructor. If the object isn't going to be changed, pass by const reference.

>So, the only thing I have to write the code for is the
Correct.

>I get an error saying that Ive got to many parameters
You're still defining it as a member function. See my second example using a friend and match your code to that.

>It's mentioned in the exercise to write it this way in main!
It's always written that way unless you want to do it without the abstraction. Your error is trying to mix a non-member operator overload with a member operator overload. You have to do one or the other. ;)

>I forgot to mention making it a friend in my other post, sorry.
Oh Narue, don't worry about that, I'm glad that you take the effort of helping me out and explaining those things ;)

>Any operations that can be made non-member functions or non-member friends should be
1) How do you know when it has to be included into a class?
2) Does this mean that considering I have to write the operators /, + and - aswell, I could best write does outside of the class and use a friend?

>operator*=
Which is the use of this operator?

>1) How do you know when it has to be included into a class?
If it effects the state of an object of that class then chances are good it should be a member. Since operator* doesn't change either the left or right operands, you can make it a non-member without losing anything.

>2) Does this mean that considering I have to write the operators /, + and -
>aswell, I could best write does outside of the class and use a friend?
Yes.

>Which is the use of this operator?
a *= b is equivalent to a = a * b. As a side note on design, if you support operator*= then you should support operator* as well. Users of your class will expect that behavior 9 times out of 10.

damn, this is confusing, im staying out of other people's threads :D

Very much appreciated :!:

Hi Narue,

Ive been writing the operator/ and didn't have any problems since it's just a small difference towards the operator* (switching numerator/operator from the second value).
I wrote it like you did in your example and it worked out fine.

Now, I'm writing the operator+ syntax the same way as the previous once, but I'm getting an error message saying this:

C:\Program Files\Microsoft Visual Studio\MyProjects\OefeningenLeenAmmeraal\LAOef4_8\LAOef4_8.cpp(30) : fatal error C1001: INTERNAL COMPILER ERROR
(compiler file 'msc1.cpp', line 1786)
Please choose the Technical Support command on the Visual C++
Help menu, or open the Technical Support help file for more information :eek:

I read the information given on the Help menu, but euh, well euh, remember that CHINEES thingy :cheesy:

Question is, could you please explain WHY this is happening :?:

When I rewrite this without using 'friend' I offcourse get the message that I have to many parameters/arguments. Changing this to one argument and using Fraction Fraction::operator+ (....) gives no problem and works out as it should.

That's a compiler panic, I've only seen it with Microsoft compilers. :rolleyes: Post your code, because in my example you should only need to change * to + for an example of how to set up operator+.

Ok, I was trying out the + operator but it's not finished yet.

#include "stdafx.h"
#include <iostream>

using namespace std;

short gcd(short numerator, short denominator);

class Fraction
{
public:
	Fraction ( short a = 0, short b = 0) : numerator (a), denominator (b){}
	
	friend Fraction operator* (const Fraction& firval, const Fraction& secval);
	friend Fraction operator/ (const Fraction& firval, const Fraction& secval);
	friend Fraction operator+ (const Fraction& firval, const Fraction& secval);

	Fraction reduce();

	void print()
	{
		cout<< numerator << "/" << denominator <<endl;
	}

private:
	short numerator, denominator;
};

Fraction operator* (const Fraction& firval, const Fraction& secval)
{
		Fraction result;
		
		result.numerator = firval.numerator * secval.numerator;
		result.denominator = firval.denominator * secval.denominator;

		result.reduce();

		return result;
}

Fraction operator/ (const Fraction& firval, const Fraction& secval)
{
	Fraction result;

	result.numerator = firval.numerator * secval.denominator;
	result.denominator = firval.denominator * secval.numerator;

	result.reduce();

	return result;
}

Fraction operator+ (const Fraction primval, const Fraction& secval)
{
	Fraction result;

	result.denominator = scd(numerator, denominator);

	result.numerator = numerator + secval.numerator;

	return result;
}

Fraction Fraction::reduce()
{
	short div = gcd(numerator, denominator);

	numerator /= div;
	denominator /= div;

	return *this;
}

int main()
{
	Fraction fract1 (3, 8), fract2 (4, 5), c;

	fract1.print();
	fract2.print();

	c = fract1 * fract2;

	c.print();

	c = fract1 / fract2;

	c.print();

	c = fract1 + fract2;

	c.print();

	return 0;
}

short gcd(short numerator, short denominator)
{
	short temp = 0;

	do
	{
		temp = (denominator% numerator);
		denominator = numerator;
		numerator = temp;
	}
	while (denominator% temp != 0);

	return temp;
}

short scd(short numerator, short denominator)
{
	short mult;

	return mult;
}

If I use this code, then I get the error.

>If I use this code, then I get the error.
I'm not surprised. scd is used before it's declared, your definition of operator+ differs from the declaration enough to be completely unique (look closely at the first parameter), and since operator+ isn't a member function, you have to pick which object to get numerator and denominator from. That last point may require some explanation:

result.numerator // numerator from result
numerator // Doesn't exist, operator+ isn't called on behalf of an object

Narue, I'll show you two versions,

When using: friend fraction operator+ (...) it doesn't work!

#include "stdafx.h"
#include <iostream>

using namespace std;

short gcd(short numerator, short denominator);

class Fraction
{
public:
	Fraction ( short a = 0, short b = 0) : numerator (a), denominator (b){}
	
	friend Fraction operator* (const Fraction& firval, const Fraction& secval);
	friend Fraction operator/ (const Fraction& firval, const Fraction& secval);
	friend Fraction operator+ (const Fraction& firval, const Fraction& secval);

	Fraction reduce();

	void print()
	{
		cout<< numerator << "/" << denominator <<endl;
	}

private:
	short numerator, denominator;
};

Fraction operator* (const Fraction& firval, const Fraction& secval)
{
		Fraction result;
		
		result.numerator = firval.numerator * secval.numerator;
		result.denominator = firval.denominator * secval.denominator;

		result.reduce();

		return result;
}

Fraction operator/ (const Fraction& firval, const Fraction& secval)
{
	Fraction result;

	result.numerator = firval.numerator * secval.denominator;
	result.denominator = firval.denominator * secval.numerator;

	result.reduce();

	return result;
}

Fraction operator+ (const Fraction& firval, const Fraction& secval)
{
	Fraction result;

	short mult = gcd( numerator, denominator);

	result.denominator = (denominator * secval.denominator) / mult;
	result.numerator = (numerator * secval.denominator) + (secval.numerator * denominator);

	result.reduce();

	return result;
}

Fraction Fraction::reduce()
{
	short div = gcd(numerator, denominator);

	numerator /= div;
	denominator /= div;

	return *this;
}

int main()
{
	Fraction fract1 (1, 3), fract2 (2, 9), c;

	cout<<"Fraction 1 and 2 are:"<<endl;
	fract1.print();
	fract2.print();cout<<endl;

	cout<<"Multiplied:"<<endl;
	c = fract1 * fract2;

	c.print();cout<<endl;

	cout<<"Divided:"<<endl;
	c = fract1 / fract2;

	c.print();cout<<endl;

	cout<<"Added:"<<endl;
	c = fract1 + fract2;

	c.print();cout<<endl;

	cin.get();

	return 0;
}

short gcd(short numerator, short denominator)
{
	short temp;

	do
	{
		temp = (denominator% numerator);
		denominator = numerator;
		numerator = temp;
		if (temp == 0)
			return 1;
	}
	while (denominator% numerator != 0);

	return temp;
}

When using: Fraction operator+ (...) it works :o

#include "stdafx.h"
#include <iostream>

using namespace std;

short gcd(short numerator, short denominator);

class Fraction
{
public:
	Fraction ( short a = 0, short b = 0) : numerator (a), denominator (b){}
	
	friend Fraction operator* (const Fraction& firval, const Fraction& secval);
	friend Fraction operator/ (const Fraction& firval, const Fraction& secval);

	Fraction operator+ (const Fraction& secval);

	Fraction reduce();

	void print()
	{
		cout<< numerator << "/" << denominator <<endl;
	}

private:
	short numerator, denominator;
};

Fraction operator* (const Fraction& firval, const Fraction& secval)
{
		Fraction result;
		
		result.numerator = firval.numerator * secval.numerator;
		result.denominator = firval.denominator * secval.denominator;

		result.reduce();

		return result;
}

Fraction operator/ (const Fraction& firval, const Fraction& secval)
{
	Fraction result;

	result.numerator = firval.numerator * secval.denominator;
	result.denominator = firval.denominator * secval.numerator;

	result.reduce();

	return result;
}

Fraction Fraction::operator+ (const Fraction& secval)
{
	Fraction result;

	short mult = gcd( numerator, denominator);

	result.denominator = (denominator * secval.denominator) / mult;
	result.numerator = (numerator * secval.denominator) + (secval.numerator * denominator);

	result.reduce();

	return result;
}

Fraction Fraction::reduce()
{
	short div = gcd(numerator, denominator);

	numerator /= div;
	denominator /= div;

	return *this;
}

int main()
{
	Fraction fract1 (1, 3), fract2 (2, 9), c;

	cout<<"Fraction 1 and 2 are:"<<endl;
	fract1.print();
	fract2.print();cout<<endl;

	cout<<"Multiplied:"<<endl;
	c = fract1 * fract2;

	c.print();cout<<endl;

	cout<<"Divided:"<<endl;
	c = fract1 / fract2;

	c.print();cout<<endl;

	cout<<"Added:"<<endl;
	c = fract1 + fract2;

	c.print();cout<<endl;

	cin.get();

	return 0;
}

short gcd(short numerator, short denominator)
{
	short temp;

	do
	{
		temp = (denominator% numerator);
		denominator = numerator;
		numerator = temp;
		if (temp == 0)
			return 1;
	}
	while (denominator% numerator != 0);

	return temp;
}

What am I doing wrong :-|

This article has been dead for over six months. Start a new discussion instead.