I'm relatively new to C++ programming. I'm studying how do classes work, and I have a problem with the following code:
#include <iostream>
using namespace std;
class time
{
public:
time();
void settime (int, int, int);
void printuniversal ();
void printstandard ();
private:
int hour;
int minute;
int second;
};
time::time()
{
hour = minute = second = 0;
}
void time::settime (int h, int m, int s)
{
hour = (h >= 0 && h < 24) ? h : 0;
minute = (m >= 0 && m < 60) ? m : 0;
second = (s >= 0 && s < 60) ? s : 0;
}
void time::printuniversal()
{
cout << hour << ":" << minute << ":" << second << ":" << endl;
}
void time::printstandard()
{
cout << ((hour == 0 || hour == 12) ? 12 : hour % 12) << ":" << minute << ":" << second << (hour < 12 ? "AM" : "PM") << endl;
}
int main ()
{
time t;
cout << "Initial universal time: " << t.printuniversal();
cout << "\nInitial standard time: " << t.printstandard();
t.settime(13,27,6);
cout << "\nNew universal time: " << t.printuniversal();
cout << "\nNew standard time: " << t.printstandard();
return 0;
}
The mistake I get is: classi.cpp:42:6: error: expected ‘;’ before ‘t’ classi.cpp:43:39: error: ‘t’ was not declared in this scope
Is there something I didn't quite understand about classes? Why doesn't it recognize t a a "time" variable?
Variable is basically nothing but the name of a memory location that we use for storing data. We can change the value of a variable in C or any other language, and we can also reuse it multiple times. We use symbols in variables for representing the memory location- so that it becomes easily identifiable by any user.
A variable given in a C program will have two of the properties: storage class and type. Here, type refers to any given variable's data type, while the storage class determines that very variable's lifetime, visibility, and also its scope.
The four storage classes in C are declared in a block or program with the storage class specifiers, auto, register, extern, static. There is one more storage class specifier, 'typedef' used in the syntactic form, and does not reserve storage. The specifiers instruct the compiler on storing the variables.
This should teach you not to have nasty using
directives such as:
using namespace std;
And especially not at namespace scope (even worse if in header files). There is a function in the standard library called std::time()
, whose name is clashing with the name of your type.
This ambiguity can be solved by using the class
keyword in the declaration of t
:
class time t;
However, a much better way would be to remove the using
directive and qualify the names of entities from the standard namespace, thus writing (for instance):
std::cout << "Initial universal time: "
// ^^^^^
Notice, that this may not be enough, since library implementations are allowed to put entities from the C standard library in the global namespace. In this case, removing the nasty using
directive would not help resolving the ambiguity.
Therefore, I would also suggest avoiding to give your own entities (types, functions, variables, ...) the same name as entities from the standard library, or to put them in your own namespace at least.
Moreover, expressions such as:
cout << "Initial universal time: " << t.printuniversal();
// ^^^^^^^^^^^^^^^^^^^^^
// printuniversal() returns void!
Are ill-formed, since printuniversal()
returns void
. You should just do:
cout << "Initial universal time: ";
t.printuniversal();
The same applies of course to all similar expressions
You shouldn't name your class time
, or you should avoid using using namespace std
. Instead, you can do statements like using std::cout
, using std::endl
, etc. I personally never use "using", always leave std::, it makes easier my searches in the source code.
Anyway, I checked here, removing using namespace std
doesn't really help (see discussion above). Play safe and change name to the class. Anyway, the above suggestions stay.
An alternative to removing the "using namespace std" directive is to place your code in a namespace to avoid clashing names. This can be done as follows:
namespace time_utils
{
class time
{
public:
time();
void settime (int, int, int);
void printuniversal ();
void printstandard ();
private:
int hour;
int minute;
int second;
};
};
time_utils::time::time()
{
hour = minute = second = 0;
}
The purpose of namespaces is to avoid clashing names.
Later on there are compilation errors when calling functions in the cout stream, so you can split them up like so:
int main ()
{
my_code::time t;
cout << "Initial universal time: ";
t.printuniversal();
cout << "\nInitial standard time: ";
t.printstandard();
t.settime(13,27,6);
cout << "\nNew universal time: ";
t.printuniversal();
cout << "\nNew standard time: ";
t.printstandard();
return 0;
}
That's because those functions are returning void. The alternative there is to have those functions return std::string instead.
Hope this offers an alternative insight.
Cheers,
Simon.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With