Working with the big methods

I am working on this program, but I am hugely stuck. This is dealing with the big methods: normal constructor, lvalue copy constructor, lvalue operator=, and destructor. I do not understand how to do the lvalue methods and the accessors to this. Any suggestion or tips that would be helpful.

Prompt:
A class named Time stores hours and minutes as unsigned shorts. (To be a proper C++11 programmer, you should use the type uint8_t, which is defined in the std namespace in the header cstdint.) Hours must always be in the range 0 – 23 and minutes, 0 – 59, both inclusive. The class must have one normal constructor that accepts zero or two parameters that default to 0. You must implement the lvalue copy constructor and the lvalue operator=. You must disable the rvalue copy constructor and operator=, and use the default destructor. The class must have two public accessors as follows. to_string_24 must return a 5-character string formatted as hh:mm, while to_string_ap must return a string formatted as [h]h:mm xM where x is either A or P. Finally, the class must have a public method named tick that increments the stored time by one minute, keeping the hours and minutes consistent. The class can have no other public methods, and no other fields.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
  #ifndef TIME
#define TIME

#include <iostream>
using namespace std;

class Time
{
   private:
   uint 8_t;
   unsigned short hours;
   unsigned short mins;
   char ampm;
   public:
   
   //constructor with default value
   explicit Time()
   {
   }
   //lvalue copy constructor with lvalue reference
   Time(const Time & rhs)
   {
      
   }
   void setTime(int &hour, int &min)
   {
      if(hour<12)
      {
         hours=hour;
         ampm='a';
      }
      else
      {
         hours=hour-12;
         mins=min;
         ampm='p';
      }
   }
   int getHours()
   {
      return hours;
   }
   int getMins()
   {
      return mins;
   }
   void printTime()
   {
      cout<<getHours()<< ":"<<getMins()<<endl;
   }
   //accessor
   string to_string_24() const
   {
      return 
   }
   //accessor
   string to_string_ap() const
   {
      return
   }
   
   
};
Last edited on
There is no reason to implement those methods for this class. The compiler-generated default ones are correct, here.

This is a case where the rule of zero applies:
http://en.cppreference.com/w/cpp/language/rule_of_three

Do not place using namespace xxx in a header file. Doing so has the potential to silently change the meaning of code in every file which includes it, either directly or indirectly.

Such name collisions are often present on some implementations and not on others, and the problems that manifest can be exceedingly difficult to diagnose. In class, this problem usually appears as code that works for you but fails to compile or (if you're unlucky) does the wrong thing on the grader's machine.
Last edited on
Hello jlin55,

I started working on this before I saw mbozzi's post, so I added a link I did not think of at first. The use of "explicit" is not something I am familiar with, but my quic research leads me to believe it will not work here.

Read the comments in the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#ifndef TIME
#define TIME

// Both these header files should not be in this heder file, but in the main file.
#include <iostream>
#include <cstdint>  // <--- Missing.

using namespace std;  // <--- Not a good idea to use in a header file.
// See http://www.lonecpluspluscoder.com/2012/09/22/i-dont-want-to-see-another-using-namespace-xxx-in-a-header-file-ever-again/

class Time
{
private:
	uint 8_t;  // <--- Wrong. should be.
	uint8_t variableName;  // <--- Correct usage.
	unsigned short hours;
	unsigned short mins;
	char ampm;
public:

	//constructor with default value
	explicit Time()  // <--- Check on the use of "explicit". I do not think it works here.
	{
		// <--- Should initialize all class variables.
	}

	//lvalue copy constructor with lvalue reference
	Time(const Time & rhs)
	{
		// <--- I believe there is something missing.
	}

	void setTime(int &hour, int &min)  // <--- Passing y reference is not needed. "hour" and "min" are not changed by the function.
	{
		if (hour<12)
		{
			hours = hour;
			ampm = 'a';
		}
		else
		{
			hours = hour - 12;
			mins = min;
			ampm = 'p';
		}
	}

	int getHours()
	{
		return hours;
	}

	int getMins()
	{
		return mins;
	}

	void printTime()
	{
                // <--- Being defined inside the class you do not need to use the getter functions just the variable names.
		cout << getHours() << ":" << getMins() << endl;
	}

	//accessor
	string to_string_24() const  // <--- Missing a parameter of what to turn into a string.
	{
		return  // <--- Missing what to return.
		// Maybe something like.
		// return std::to_string(variable);
	}

	//accessor
	string to_string_ap() const
	{
		return 
	}


};

// <--- Missing.
#endif  // TIME 


The only part I am still confused on is the use of "uint8_t" and unsigned short. On my VS IDE "unit8_t" is a typedef for an unsigned char and "unit16_t" is an unsigned short. Since the highest number is 59 an unsigned char will work.

Sorry, but someone with more experience using "explicit" will have to cover that.

Hope that helps,

Andy
For constructors with no parameters, explicit does nothing.
Ok I will get rid of "explicit"
Here is what I have so far. Still working on the other directions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#ifndef TIME
#define TIME

#include <iostream>
#include <cstdint>

class Time
{
   private:
   uint8_t ;
   unsigned short hours;
   unsigned short mins;
   char ampm;
   public:
   
   //constructor with default value
    Time()
   {
   }
   //lvalue copy constructor with lvalue reference
   Time(const Time & rhs)
   {
      
   }
   Time()
   {
      hours=0;
      mins=0;
   }
   Time(uint8_t hour, uint8_t min)
   {
      hour=hours;
      min=mins;
   }
   
  // void setTime(int &hour, int &min)
  // {
   //   if(hour<12)
   //   {
   //      hours=hour;
    //     ampm='a';
     // }
    //  else
    //  {
    //     hours=hour-12;
    //     mins=min;
    //     ampm='p';
    //  }
  // }
   int getHours()
   {
      return hours;
   }
   int getMins()
   {
      return mins;
   }
   void printTime()
   {
      cout<<getHours()<< ":"<<getMins()<<endl;
   }
   //accessor
   string to_string_24() const
   {
      return hour + ":" + min
   }
   //accessor
   string to_string_ap() const
   {
      return 
   }
   
   
};
#endif //Time 
Maybe my English is even worse I’ve supposed so far, but these requirements sound either contradictory or deceitful.
The assignment asks:
The class must have two public accessors as follows. to_string_24 must return a 5-character string formatted as hh:mm, while to_string_ap must return a string formatted as [h]h:mm xM where x is either A or P

How do you interpret the statement “5-character string”? Because it sounds like a C-style char mystring[5].
But, if this array is dynamically allocated inside one of the mentioned methods, then it should be deleted inside the destructor, while a previous statement says:
use the default destructor
, which can’t be aware of that array.
On the other hand, if you introduce a C-style string between the properties, that would justify the request of a non default copy constructor (which otherwise is incomprehensible, as mbozzi pointed out), but it would contradict the following statement:
The class can have no other public methods, and no other fields.


So, please, could someone help me understanding better? I’m I just making things more complicated than they are or am I really missing something?

jlin55, could you please clarify me if this is an assignment and if you’re allowed to use std::string or not?
If this is an assignment, have you already read here?
http://www.cplusplus.com/forum/beginner/1/
Don't post homework questions
Programmers are good at spotting homework questions; most of us have done them ourselves. Those questions are for you to work out, so that you will learn from the experience. It is OK to ask for hints, but not for entire solutions.

I’m asking it you because it doesn’t seem you’re following the suggestion you’ve already received, as if you were asking for the solution. Is that what you want? A solution with std::string or C-style strings?
How do you interpret the statement “5-character string”? Because it sounds like a C-style char mystring[5].


That doesn't seem right. The original context was a format of hh:mm which would require a 6-element c-style character array. I'd say a std::string is safer since it doesn't require any special precautions which the use of a char * pointer might.

Also, the naming to_string_24 and to_string_ap echoes the style of standard library functions which return a std::string. That might not mean anything, but it could be a clue to the intention.
Last edited on
Read the assignment one sentence at a time and see if you can translate it into something for the header. When you're done, go back and re-read the assignment to see if you missed anything. Repeat until you have everything needed in the header. Then fill in the code:

A class named Time
1
2
3
4
5
#ifndef TIME
#define TIME
class Time {
};
#endif 


stores hours and minutes as unsigned shorts.
1
2
private:
short hours, minutes;

(To be a proper C++11 programmer, you should use the type uint8_t, which is defined in the std namespace in the header cstdint.)

Oops, so that should be
1
2
3
#include <cstdint>
...
uint8_t hours, minutes;


Hours must always be in the range 0 – 23 and minutes, 0 – 59, both inclusive.

Okay, we'll have to implement that somewhere. TBD.

The class must have one normal constructor that accepts zero or two parameters that default to 0.

I'm not sure that you can accept 0 or 2 params in one constructor but here's one that accepts 0, 1, or 2:
Time(std::uint8_t h=0, std::uint8_t s=0);

You must implement the lvalue copy constructor and the lvalue operator=.
1
2
    Time(const Time & rhs);
    Time &operator=(const Time &rhs);

You must disable the rvalue copy constructor and operator=,
1
2
    Time(Time &&) = delete;
    Time &operator=(Time &&rhs) = delete;

and use the default destructor.
~Time() = default;
The class must have two public accessors as follows. to_string_24 must return a 5-character string formatted as hh:mm,
std::string to_string_24() const;

while to_string_ap must return a string formatted as [h]h:mm xM where x is either A or P.
std::string to_string_ap() const;
Finally, the class must have a public method named tick that increments the stored time by one minute, keeping the hours and minutes consistent.
void tick();

The class can have no other public methods, and no other fields.

That's it. You can't have anything else. Specifically, you can't have an ampm member.

Put that all together. That's the class you have to implement.
I was told that we can have using namespace std; in our header class
Thank you for your kind answer, Chervil; you have a good point.
I can drop my C-style string hypothesis without a tear :-) but what’s left is a requirement for two super-trivial constructor in a class where the default ones would be enough.
One's "super-trivial" is another's "hugely stuck". The learning must start from somewhere.


Namespaces, headers ... a while ago, when namespaces were new,
Herb Sutter wrote some about them:
http://www.gotw.ca/gotw/053.htm
This is what I have so far.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#ifndef TIME
#define TIME

#include <iostream>
#include <cstdint>

using namespace std;
class Time
{
   private:
   uint8_t hours, mins;
   
   
   
   public:
   
   //normal constructor
   Time(uint8_t hour=0, uint8_t min=0):hours{hour}, mins{min}
   {
     
   }
   //lvalue copy constructor with lvalue reference
   Time(const Time & rhs):hours{rhs.hours},mins{rhs.mins}
   {
      //nothing
   }
   //lvalue operator=constructor
   Time & operator=(const Time & rhs)
   {
      hour=rhs.hours;
      min=rhs.mins;
   }
   
   
   
   //accessor
   string to_string_24() const
   {
            string time;
      if(hours<10)
      {
         if(mins<10)
         {
            time = '0' + to_string(hours) + '0' + ':'+ to_string(mins);
         }
         else
         {
            time =  '0' + to_string(hours) + ':' +to_string(mins);
         }
         
      }
      
      else
      {
         if( mins<10)
         {
            time = to_string(hours) + '0' + ':' + to_string(mins);
         }
         else
         {
            time = to_string(hours) + ':' + to_string(mins);
         }
      }
      
   }
   //accessor
   string to_string_ap() const
   {
      string ampm;
      string time;
      if(hours<10)
      {
         if(mins<10)
         {
            time = '0' + to_string(hours) + '0' + ':'+ to_string(mins);
         }
         else
         {
            time =  '0' + to_string(hours) + ':' +to_string(mins);
         }
         
      }
      
      else
      {
         if( mins<10)
         {
            time = to_string(hours) + '0' + ':' + to_string(mins);
         }
         else
         {
            time = to_string(hours) + ':' + to_string(mins);
         }
      }
      
      if(hours < 12)
      {
         ampm="AM";
      }
      else
      {
         ampm="PM";
      }
      return time + ampm;
   }
   //disable constructors
   Time(const Time & rhs) = delete;
   Time & operator=(Time && rhs)=delete;
   
   //destructor
   ~Time()
   {
      //nothing
   }
   //tick method
   void tick()
   {
      if(mins==59)
      {
         hours++;
         mins=0;
      }
      else 
      {
         mins++;
      }
   }
   
   
};
#endif //Time
   
   
1. When you tick past 23:59 ...

2. Compare your outputs to the required format. You should notice 4 deviations.
a. Should 9:05 print (in 24): "090:5" or "09:05"?
b. Should 9:05 print (in ap): "090:5AM" or "9:05 AM"?
c. Should 13:15 print (in ap): "13:15PM" or "1:15 PM"?

3. In ap() you do construct 'time' and 'ampm' separately and then concatenate them.
Would it be simpler or more complex to construct hours and minutes separately?

4. Compare lines 23 and 107.

5. From which header do 'string' and 'to_string' come from?
Can you trust every Standard Library implementation do that?

6. Where do you need <iostream>?
2.
a. should be "09:05 AM"
c. should be "1:15 PM"

How do i fix those?

I will get rid of iostream

Also did I disable my constructors right?
Last edited on
Hours must always be in the range 0 – 23 and minutes, 0 – 59, both inclusive.

You don't currently guarantee this. For example, Time(10,62) will set hours to 10 and mins to 62. What should they be set to?
Topic archived. No new replies allowed.