在数据成员或方法中存储类常量是否更好?

时间:2009-03-15 11:18:49

标签: c++ constants members

我最近写了一个渲染B样条曲线的类。这些曲线由许多控制点定义。最初,我打算使用8个控制点,所以我在课堂上添加了一个常量,如下所示:

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

现在我想扩展这个类以允许任意数量的控制点。所以我想把它改成:

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

问题在于,在方法中存储常数是否更好,以促进适应性。换句话说,这样开始不是更好:

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

这样做的好处是我可以在相关方法中更改一个符号,而不是移动常量等。

这是一个好习惯还是坏习惯?

9 个答案:

答案 0 :(得分:2)

int getControlPointCount() {return _controlPointCount;}

这是一个访问者。像litb指出的那样,为访问器交换const静态并不是真正的好处。您真正需要面向未来的可能是一对访问者和变异者。

int getControlPointCount() {return _controlPointCount;} // accessor

我还会为访问者提供一个design-const并将其设为:

int getControlPointCount() const {return _controlPointCount;} // accessor

和相应的:

void setControlPointCount(int cpc) { _controlPointCount = cpc;} //mutator

现在,与静态对象的最大区别在于控制点计数不再是类级别属性,而是实例级别1。这是设计更改。你想要这样吗?

Nit:您的班级静态计数为public,因此不需要访问者。

答案 1 :(得分:1)

为了更好地回答您的问题,还应该知道如何设置controlPointCount变量。它是否在您的课堂之外?在这种情况下,您还应该定义一个setter。或者曲线类是唯一负责设置的?它是仅在编译时还是在运行时设置的。

无论如何,即使以这种形式避免使用幻数:

int getControlPointCount() {return 8;}

这样更好:

int getControlPointCount() {return CONTROL_POINT_COUNT;}

方法的优点是您可以修改内部实现(使用常量值,从配置文件中读取,动态更改值),而不会影响类的外部。

答案 2 :(得分:1)

通常我赞成尽可能少地手动保持联轴器。

曲线中的控制点数量是曲线中控制点的数量。它不是一个可以随意设置的自变量。

所以我通常会公开一个const标准容器引用:

class Curve
{   
    private:
        std::vector<Point>& _controlPoints;

    public:      
        Curve ( const std::vector<Point>& controlPoints) : _controlPoints(controlPoints)
        {
        }

        const std::vector<Point>& getControlPoints ()
        {
            return _controlPoints;
        }
};

如果您想知道有多少个控制点,请使用curve.getControlPoints().size()。我怀疑在大多数用例中你无论如何都需要积分和数量,并且通过暴露标准容器,你可以使用标准库的迭代器习语和内置算法,而不是计算和调用循环中的getControlPointWithIndex函数。

如果曲线类中没有其他内容,我甚至可能会:

typedef std::vector<Point> Curve;

(通常曲线不会渲染自身,因为渲染器类可以包含有关渲染管道的详细信息,将曲线保留为纯粹的几何图形)

答案 3 :(得分:0)

通常,您的所有数据都应该是私有的,并通过getter和setter访问。否则你违反了封装。也就是说,如果您公开基础数据,则将您自己和您的类锁定为该基础数据的特定表示。

在这个特定的情况下,我会做以下的事情,我想:

class Curve
{

   protected:

      int getControlPointCount() {return _controlPointCount;}
      int setControlPointCount(int c) { _controlPointCount = c; }

   private:

      static int _controlPointCount = 0;
};

答案 4 :(得分:0)

class Curve
{   
    private:
        int _controlPointCount;

        void setControlPointCount(int cpc_arg)
        {
            _controlPointCount = cpc_arg;
        }

    public:      
        curve()
        {
            _controlPointCount = 8;
        }

        int getControlPointCount() const
        {
            return _controlPointCount;
        }
};

我将创建一个这样的代码,私有的set函数,这样任何主体都无法使用控制点计数,直到我们进入下一个开发阶段。我们更新开始更新控制点计数运行。那时,我们可以将这个set方法从私有范围移到公共范围。

答案 5 :(得分:0)

在理解这个问题的同时,我对这个例子有很多概念上的问题:

  • 当控制点数量不受限制时,getControlPointCount()的返回值是多少?
    • 是MAXINT吗?
    • 它是曲线上当前的控制点数量(因此打破了说这是最大可能点数的逻辑吗?)
  • 当您实际尝试使用MAXINT点创建曲线时会发生什么?你最终会耗尽内存。

界面本身对我来说似乎有问题。与其他标准集合类一样,该类应该封装其对点数的限制,如果发生了对大小,内存或任何其他违规的限制,则其AddControlPoint()应该返回错误。

至于具体答案,我同意kgiannakakis:成员函数允许更多的灵活性。

答案 6 :(得分:0)

我倾向于通过执行程序对所有“稳定”值使用配置+常量(默认值)。使用无法更改的值的普通常量(360度 - > 2 pi弧度,60秒 - > 1分钟)或其更改将破坏正在运行的代码(使算法不稳定的算法的最小/最大值)。

您正在处理一些不同的设计问题。首先,您必须知道控制点的数量是类级别还是实例级别值。然后它是否是两个级别中的任何一个的常量。

如果所有曲线必须在应用程序中共享相同数量的控制点,那么它是类级别(静态)值。如果不同的曲线可以具有不同数量的控制点,那么它不是类级别值,而是实例级别1。

在这种情况下,如果控制点的数量在曲线的整个生命周期内保持不变,那么它就是一个实例级别常量,如果它可以改变,那么它也不会在这个级别保持不变。

// Assuming that different curves can have different 
// number of control points, but that the value cannot 
// change dynamically for a curve.
class Curve
{
public:
   explicit Curve( int control_points )
      : control_points_( control_points )
   {}
   // ...
private:
   const int control_points_;
};

namespace constant
{
   const int spline_control_points = 8;
}
class Config
{
public:
   Config();
   void readFile( std::string const & file );

   // returns the configured value for SplineControlPoints or
   // constant::spline_control_points if the option does not 
   // appear in config.
   int getSplineControlPoints() const;
};

int main()
{
   Config config;
   config.readFile( "~/.configuration" ); // read config

   Curve c( config.getSplineControlPoints() );
}

答案 7 :(得分:0)

对于整数类型我通常使用:

class Curve
{
   public:
      enum 
      {
          CONTROL_POINT_COUNT = 8
      };
};

如果常量不需要除类实现之外的任何实体,我在* .cpp文件中声明常量。

namespace
{
const int CONTROL_POINT_COUNT = 8;
}

答案 8 :(得分:0)

通常不应在方法内定义常量。您选择的示例有两个独特的功能。首先,它是一个吸气剂;第二,返回的类型是int。但是定义常量的关键是不止一次地使用它们,并且能够以方便的方式引用它们。键入“8”而不是“controlPointCount”可能会节省您的时间,并且可能不会产生维护成本,但如果始终在方法中定义常量,则通常不会这样。