I have a class CS which is to represent the co-ordinate system in 3D i.e.(x, y, z)
class CS
{
private:
double x;
double y;
double z
You can't really represent it in the same number of bits without having a sentinel. If 0 is a valid number, then you can't use it. If you try and foist null handling into a value type you will have fundamentally incorrect and unmaintainable code.
When handling nulls properly you would expect to see an interface like this:
struct foo {
virtual ~foo() {}
virtual bool getX(double &val) = 0;
virtual bool getY(double &val) = 0;
virtual bool getZ(double &val) = 0;
};
The implementation can have a flag that it checks before access.
void some_func(foo *f) {
double x, y, z;
if (f->getX(x) && f->getY(y) && f->getZ(z)) {
cout << x << ", " << y << ", " << z << endl;
} else {
throw std::logic_error("expected some values here");
}
}
You don't want to use an invalid value and not know it. Having to check the return values is tedious obviously, but it gives you the most control. You could also have helpers or overloads that would throw if they weren't valid.
struct bar {
double getX() {
if (!valid)
throw std::logic_error("bar is not valid");
return x;
}
bool valid;
double x, y, z;
}
For me, the difference between foo
and bar
is that low level code handling the data shouldn't enforce a policy of whether the data is there or not. At higher levels of abstraction you can and should have expectations of whether the data should valid when you go to use it. The both can exist in a system, but foo
is necessary.