Problem 1:
Person a();
A vexing parse. This does not declare a variable and invoke the constructor, it declares function a
that returns a Person
.
Solution:
Person a;
but this sets up problem 2:
There is no default constructor. Specifying Person(int _age)
defines a non-default constructor and this blocks the compiler from generating a default (parameter-less) constructor. This is actually a win for you because your stated goal is to not be able to construct a Person
without parameters.
You cannot
Person a;
You must
Person a(<an int>);
This does not prevent a user from
Person a(-1);
Which makes little sense for anyone not from Ork. This sets up a great example for use of an exception in a constructor and exposes problem 3:
There are two ways out of a constructor that don't end the program: With a constructed object and by a thrown exception. Both throwing and catching an exception that signals construction has failed in a constructor is unusual because it allows an improperly constructed object to be returned.
So
Person(int _age)
{
age = _age;
try
{
if (age == -1) // probably should reject age < 0
{
throw 1;
}
}
catch (int x)
{
cout << "You have to specify person's age" << endl;
}
}
Actually causes the problem you are trying to avoid.
Solution:
Person(int _age)
{
age = _age;
if (age == -1)
{
throw 1;
}
}
and in main
int main(void)
{
try
{
Person a();
// use a
return 0;
}
catch (int x)
{
cout << "You have to specify person's age" << endl;
return -1;
}
}
There is one big improvement that can be made: Make exceptions meaningful
Throwing 1 contains too little context to be meaningful. You can throw and catch a custom exception, but for something simple like this std::runtime_error
from `
Person(int _age)
{
if (_age == -1)
{
throw std::runtime_error("You have to specify person's age");
// do not new an exception. It's hard to clean up and free the memory
}
age = _age; // why assign then test? Save a clock cycle.
}
and in main
int main(void)
{
try
{
Person a();
// use a
return 0;
}
catch (const std::exception & e) // where possible catch by constant reference
{
cout << e.what() << endl;
return -1;
}
}