Imagine a class:
// header file
class Vector {
private:
float _data[4];
public:
Vector(float x, float y, float z, float w);
static const Vector ORIGIN;
};
// source file
const Vector Vector::ORIGIN(0.0, 0.0, 0.0, 1.0);
Vector::Vector(float x, float y, float z, float w) {
_data[0] = x;
_data[1] = y;
_data[2] = z;
_data[3] = w;
}
And here is another class:
// header file
class CoordinateSystem {
private:
Vector _origin;
public:
CoordinateSystem(const Vector &vector);
static const CoordinateSystem GLOBAL;
};
// source file
const CoordinateSystem CoordinateSystem::GLOBAL(Vector::ORIGIN); // <===
PROBLEM HERE
CoordinateSystem::CoordinateSystem(const Vector &vector) {
_origin = vector; // yes, the operator is defined and works
}
and the problem is, that when I try to use GLOBAL variable from the
CoordinateSystem class, its _origin variable has all the elements in _data
fields set to zeros. Why??? Is it a problem with linking? Compiling? Not
being able to determine a value of one constant variable when used to
initiate another constant variable???
Please help.
Martin
> class Vector {
> static const Vector ORIGIN;
> class CoordinateSystem {
> static const CoordinateSystem GLOBAL;
> };
> const CoordinateSystem CoordinateSystem::GLOBAL(Vector::ORIGIN); // <===
> PROBLEM HERE
That's the problem of initialization of variables are program startup. The
compiler may write code that initializes the variables in Vector.cpp first
then Coordinate.cpp, in which case you're OK. But if it initializes the
variables in Coordinate.cpp first, then you're in trouble because
Vector::ORIGIN is used before it is initialized.
(1) There's a simple solution. Use static functions instead of static
variables.
class Vector {
static const Vector& ORIGIN();
};
const Vector& Vector::ORIGIN() {
static const Vector origin(0,0,0,1);
return origin;
}
If the system decides to initialize Coordinate.cpp first, it will still call
Vector::ORIGIN() which will construct the vector as needed.
A disadvantage of this method is that each time you call Vector::ORIGIN()
the system will generate code to see if the static variable of the function,
namely 'origin' in my code above, has been constructed. This could be a
performance hit. You only need this code the first time.
If the performance hit is negligible, don't worry.
(2) There is more complex solution involving counters, saving/restoring,
etc. But as your Vector is const, I'm not sure if this solution is possible
here, unless you're willing to use const_cast (which I don't recommend).
(3) Finally, in your case you have another solution. Since class Vector is
so simple declare a const Vector in the header file.
// Vector.
class Vector { };
const Vector ORIGIN(0,0,0,1);
Every file that includes Vector.h gets its own ORIGIN. If class Vector were
a big class, this could be a space problem. But of course this isn't the
case here.
And I think this is the best solution for your problem.
--
+++++++++++
Siemel Naran
I liked Siemel Naran's ideas. Here's another idea.
class Vector {
// as above except remove the static const Vector
Vector();
};
// source
Vector::Vector() {
_data[0] = 0.0;
_data[1] = 0.0;
_data[2] = 0.0;
_data[3] = 1.0;
}
Now in your CoordinateSystem class, _origin will be naturally crated as
a holding 0, 0, 0, 1