Search code examples
c++constantsmembers

Is it better to store class constants in data members or in methods?


I recently wrote a class that renders B-spline curves. These curves are defined by a number of control points. Originally, I had intended to use eight control points, so I added a constant to the class, like so:

class Curve
{
   public:
      static const int CONTROL_POINT_COUNT = 8;
};

Now I want to extend this class to allow an arbitrary amount of control points. So I want to change this to:

class Curve
{
   public:
      int getControlPointCount() {return _controlPointCount;}
};

The question is whether it isn't better to store constants in methods to begin with, to facilitate adaptability. In other words, isn't it better to have started thus:

class Curve
{
   public:
      int getControlPointCount() {return 8;}
};

The advantage of this is that I could have just changed one symbol in the method in question, instead of moving around constants etc.

Is this a good practice or a bad one?


Solution

  • Typically I favour maintaining as few couplings manually as possible.

    The number of control points in the curve is, well, the number of control points in the curve. It's not an independent variable that can be set at will.

    So I usually would expose a const standard container reference:

    class Curve
    {   
        private:
            std::vector<Point>& _controlPoints;
    
        public:      
            Curve ( const std::vector<Point>& controlPoints) : _controlPoints(controlPoints)
            {
            }
    
            const std::vector<Point>& getControlPoints ()
            {
                return _controlPoints;
            }
    };
    

    And if you want to know how many control points, then use curve.getControlPoints().size(). I'd suspect that in most of the use cases you'd want the points as well as the count anyway, and by exposing a standard container you can use the standard library's iterator idioms and built-in algorithms, rather getting the count and calling a function like getControlPointWithIndex in a loop.

    If there really is nothing else in the curve class, I might even go as far as:

    typedef std::vector<Point> Curve;
    

    (often a curve won't render itself, as a renderer class can have details about the rendering pipeline, leaving a curve as purely the geometric artifact)