关于 C++ 类接口设计的建议:您将如何命名这两个方法以使其显而易见?

问题描述

我有一个非常简单的具体类,它表示 2D 空间中的一个点,它有两种方法来移动给定半径和角度的点:一种修改对象本身,另一种创建另一个对象,保持第一个不变:

template<class T =double> class cls_2DPoint
{
    ...
    cls_2DPoint<T>& polar_move(const T r,const double a) noexcept
       {
        x+=r*std::cos(a); y+=r*std::sin(a); return *this;
       }
    cls_2DPoint<T> polar_moved(const T r,const double a) const noexcept
       {
        return cls_2DPoint<T>(x+r*std::cos(a),y+r*std::sin(a));
       }
    ...
    T x,y;
};

这实际上是我正在使用的代码!在审查它时,我意识到这是一个鲁莽的设计:不明显,容易出错,使用户代码的可读性降低。 由于我正在努力寻找令人信服的替代方案,因此我想在这里寻求建议:是否有命名修改和非修改方法的一般约定/指南?是否有最佳实践可以帮助我改进设计?

解决方法

我的建议。

类名使用namespace代替前缀

namespace cls2D
{
   class Point { ... };
}

添加类Vector

namespace cls2D
{
   class Point { ... };
   class Vector { ... };
}

定义运算符方法

定义适用于两种对象类型的运算符方法。如果可以的话,最好使用非成员函数。

namespace cls2D
{
   class Vector;

   class Point
   { 
      public:

         Point& operator+=(Vector v);
         Point& operator-=(Vector v);

      private:
         double x = 0;
         double y = 0;
      
   };

   class Vector
   {
      public:

         Vector& operator+=(Vector v);
         Vector& operator-=(Vector v);

      private:
         double x = 0;
         double y = 0;
   };

   Point from_polar(double r,double th);
   Point from_vector(Vector v);
   Vector from_point(Point p);

   Point operator+(Point p,Vector v);
   Point operator+(Vector v,Point p);
   Vector operator+(Vector v1,Vector v2);

   Vector operator-(Point p1,Point p2);
   Vector operator-(Vector v1,Vector v2);

}

请注意,PointVector 具有相同的成员数据。因此,很容易只使用一个类来表示两者。但是,我认为它们是两种不同的抽象,应该是不同的类。

我删除了答案中的 template 部分,以便更简单地说明这个想法。

我假设您知道如何将必要的辅助函数添加到类中。

,

我会这样命名它们:

template<class T =double> class cls_2DPoint
{
    ...

    cls_2DPoint<T>& polarMovePoint(const T r,const double a) noexcept
       {
        x+=r*std::cos(a); y+=r*std::sin(a); return *this;
       }

    cls_2DPoint<T> polarMovePointClone(const T r,const double a) const noexcept
       {
        return cls_2DPoint<T>(x+r*std::cos(a),y+r*std::sin(a));
       }
    ...
    T x,y;
};

这种类型的标签会让我知道哪个函数移动了点本身,哪个函数创建了点的克隆,然后移动了它。