I'm trying to come with a way to allow the default construction of a class, but throw an error if the user tries to access a member of the class without fully initializing the object.
Similar to how Java would allow:
1 2 3
City my_city;
my_city = new City("New York");
my_city.do_something();
but throw an error if you tried:
1 2
City my_city;
my_city.do_something();
I want my c++ code to allow:
1 2 3
City my_city;
my_city = City("New York");
print(my_city.name());
but throw an error if I try:
1 2
City my_city;
print(my_city.name());
I'm wondering if maybe there's something in a boost library I could extend my class off of that might accomplish something like this, but I'm not sure what I'm looking for.
The only other way I've come up with so far would be to put a check inside each method on the City object to make sure I've set some kind of init flag on the object before it executes.
You can try making the default constructor inaccessible.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#include <string>
class City
{
private:
City();
public:
City(const std::string& name);
};
int main()
{
City city; // <-- Will Not Compile
City city2("Hello City"); // Will Compile
return 0;
}
It's not exactly what you're looking for, but the only other alternative that I can think of is to wrap your city objects in a smart pointer. There's a pitfall to this as well, because a NullPointerException won't be thrown in C++ if you try to deference a null pointer - an unrecoverable hardware exception will occur.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#include <memory>
class City
{
public:
void doSomething(void) { }
};
int main()
{
std::scoped_ptr<City> my_city;
my_city->doSomething(); // <-- Either a debug assertion will trigger, or a hardware exception.
my_city.reset(new City);
my_city->doSomething(); // <-- Works as expected.
return 0;
}
Xander - The problem is though if default constructions succeeds that doesn't mean any of the values of the members are set to anything correct. They're all set to default values like "" or 0.
I don't want someone to be able to default construct, but then try and access a member that doesn't have a valid value in it. I want to insure that some kind of full constructor or init method has been called before allowing access to other methods.
class City
{
private:
City();
std::string name_;
public:
City(const std::string& name):name_(name);
const std::string& name()const{
return name_;
}
}
int main()
{
City city1; // <-- This line would give you a compile-time error. (default constructor inaccessible)
city1 = City("Boston");
print(city1.name()); //<- would succeed;
//but
City city1; // <-- Another compile-time error (default constructor inaccessible)
print(city1.name()); //<- This wouldn't be able to happen, as it couldn't compile.
}
int main()
{
MyClass obj;
cout << obj.GetData() << endl; //Throws an exception
obj.InitClass(1337); //Sets up the class correctly
cout << obj.GetData() << endl; //Does not throw an exception
}
@Luc Lieber
Is there any need to make the default constructor private? Why not just exclude the default constructor. Then, provided another constructor is included, no default one will be generated at all, as far as I am aware.
@ischuldt
Reading this thread carefully in its entirety, it seems to me that L B's solution is the closest to what your OP was asking for. However, I find the implications in this thread somewhat troubling.
In your OP, the Java code
1 2
City my_city;
my_city.do_something();
dies for a reason that's different than the problem raised by your OP. It's failing because my_city doesn't point to anything (equivalent of a NULL ptr in C++).
Exactly the same code in C++ actually constructs an instance (an automatic variable that's cleaned up when it falls out of scope), even though instance may not be initialized with an actual valid value of a real city.
Are you trying to port Java code to C++? I am getting the uneasy feeling that you may be trying to make C++ behave like Java or you are using Java thinking in C++...
yeah L B's solution is the one I came up with originally. I was hoping for something better than wouldn't require an if check to be added to every getter, setter and method in the class, but...
c++ may not be java, but there are some features of java that are really nice.
If you are still intent on making your C++ code safer, you can also look into assert() (C version) or static_assert() (Boost, C++0x) for a more concise way of checking for a valid object (google for examples).
here's a crazy idea. What about overloading the . operator or -> operator to automatically do the check for you so you don't have to add it all the time.