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

发布于 2024-07-16 01:45:34 字数 558 浏览 11 评论 0原文

我最近编写了一个渲染 B 样条曲线的类。 这些曲线由许多控制点定义。 最初,我打算使用八个控制点,因此我向该类添加了一个常量,如下所示:

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

现在我想扩展该类以允许任意数量的控制点。 所以我想将其更改为:

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

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

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

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

这是一种好的做法还是坏的做法?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

爱格式化 2024-07-23 01:45:34
int getControlPointCount() {return _controlPointCount;}

这是一个访问器。 正如 litb 所指出的那样,将 const static 替换为访问器并不是真正的好处。 为了面向未来,您真正需要的可能是一对访问器和修改器。

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

我还会为访问器添加一个设计常量并使其:

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

以及相应的:

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

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

Nit:您的类级别静态计数是public,因此不需要访问器。

int getControlPointCount() {return _controlPointCount;}

This is an accessor. Swapping a const static for an accessor is not really a gain as litb has pointed out. What you really need to future-proof is probably a pair of accessor and mutator.

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

I'd also throw in a design-const for the accessor and make it:

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

and the corresponding:

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

Now, the big difference with a static object is that the control-point count is no longer a class-level attribute but an instance level one. This is a design change. Do you want it this way?

Nit: Your class level static count is public and hence does not need an accessor.

梦屿孤独相伴 2024-07-23 01:45:34

通常,我倾向于手动维护尽可能少的耦合。

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

因此,我通常会公开一个 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;

通常曲线不会自行渲染,因为渲染器类可以包含有关渲染管道的详细信息,从而将曲线保留为纯粹的几何工件)

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)

瞄了个咪的 2024-07-23 01:45:34

为了更好地回答您的问题,还应该知道 controlPointCount 变量是如何设置的。 是在你们班级外面吗? 在这种情况下,您还应该定义一个 setter。 或者 Curve 类是唯一负责设置它的? 是仅在编译时设置还是也在运行时设置。

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

int getControlPointCount() {return 8;}

这更好:

int getControlPointCount() {return CONTROL_POINT_COUNT;}

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

To better answer your question, one should also know how the controlPointCount variable is set. Is it set outside from your class? In this case, you should also define a setter. Or the Curve class is the sole responsible for setting it? Is it set only on compile time or also on runtime.

Anyway, avoid a magic number even in this form:

int getControlPointCount() {return 8;}

This is better:

int getControlPointCount() {return CONTROL_POINT_COUNT;}

A method has the advantage that you can modify the internal implementation (use a constant value, read from a configuration file, alter the value dynamically), without affecting the external of the class.

陌上青苔 2024-07-23 01:45:34
class Curve
{   
    private:
        int _controlPointCount;

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

    public:      
        curve()
        {
            _controlPointCount = 8;
        }

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

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

class Curve
{   
    private:
        int _controlPointCount;

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

    public:      
        curve()
        {
            _controlPointCount = 8;
        }

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

I will create a code like this, with set function in private, so that no body can play with control point count, until we move to the next phase of development..where we update start to update the control point count at runtime. at that time, we can move this set method from private to public scope.

如何视而不见 2024-07-23 01:45:34

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

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

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

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

While understanding the question, I have a number of conceptual problems with the example:

  • What is the return value for getControlPointCount() when the number of control points is not limited?
    • Is it MAXINT?
    • Is it the current number of control points on the curve (thus breaking the logic that says that this is the largest possible number of points?)
  • What happens when you actually attempt to create a curve with MAXINT points? You will run out of memory eventually.

The interface itself seems problematic to me. Like other standard collection classes, the class should have encapsulated its limitation on number of points, and its AddControlPoint() should have returned an error if a limitation on size, memory, or any other violation has occurred.

As for the specific answer, I agree with kgiannakakis: a member function allows more flexibility.

打小就很酷 2024-07-23 01:45:34

我倾向于对程序执行过程中的所有“稳定”值使用配置+常量(默认值)。 使用普通常量表示无法更改的值(360 度 -> 2 pi 弧度,60 秒 -> 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() );
}

I tend to use configuration + constant (default value) for all 'stable' values through the execution of the program. With plain constants for values that cannot change (360 degrees -> 2 pi radians, 60 seconds -> 1 minute) or whose change would break the running code (minimum/maximum values for algorithms that make them unstable).

You are dealing with some different design issues. First you must know whether the number of control points is a class or instance level value. Then whether it is a constant at any of the two levels.

If all curves must share the same number of control points in your application then it is a class level (static) value. If different curves can have different number of control points then it is not a class level value, but rather a instance level one.

In this case, if the number of control points will be constant during the whole life of the curve then it is a instance level constant, if it can change then it is not constant at this level either.

// 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() );
}
青朷 2024-07-23 01:45:34

对于整型,我通常使用:

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

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

namespace
{
const int CONTROL_POINT_COUNT = 8;
}

For integral type I'm usualy using:

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

If constant doesn't need for any entities except class implementation I declare constants in *.cpp file.

namespace
{
const int CONTROL_POINT_COUNT = 8;
}
放赐 2024-07-23 01:45:34

一般来说,您的所有数据都应该是私有的,并通过 getter 和 setter 进行访问。 否则就违反了封装。 也就是说,如果您公开基础数据,您就会将自己和您的类锁定到该基础数据的特定表示形式中。

在这种具体情况下,我认为我会做类似以下的事情:

class Curve
{

   protected:

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

   private:

      static int _controlPointCount = 0;
};

In general, all your data should be private and accessed via getters and setters. Otherwise you violate encapsulation. Namely, if you expose the underlying data you lock yourself and your class into a particular representation of that underlying data.

In this specific case I would have done the something like the following I think:

class Curve
{

   protected:

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

   private:

      static int _controlPointCount = 0;
};
七禾 2024-07-23 01:45:34

一般来说,常量不应该在方法内部定义。 您选择的示例有两个独特的功能。 首先,它是一个吸气剂; 其次,返回的类型是 int。 但定义常量的目的是多次使用它们,并且能够以方便的方式引用它们。 键入“8”而不是“controlPointCount”可能会节省您的时间,并且似乎不会产生维护成本,但如果您始终在方法内定义常量,则通常情况并非如此。

Constants in general should not be defined inside methods. The example you're choosing has two unique features. First, it's a getter; second, the type being returned is an int. But the point of defining constants is to use them more than once, and to be able to refer to them in a convenient way. Typing "8" as opposed to "controlPointCount" may save you time, and may not seem to incur a maintenance cost, but this won't typically be true if you always define constants inside methods.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文