有人告诉我他们团队中 C++ 风格的差异。我对这个问题有自己的观点,但我感兴趣的是 优点缺点 来自每个人。

因此,如果您有一个类属性,您想通过两个 getter 来公开,一个是读/写的,另一个是只读的(即没有固定的方法)。至少有两种方法可以做到这一点:

class T ;

class MethodA
{
   public :
      const T & get() const ;
      T & get() ;

      // etc.
} ;

class MethodB
{
   public :
      const T & getAsConst() const ;
      T & get() ;

      // etc.
} ;

每种方法的优点和缺点是什么?

我对 C++ 技术/语义原因更感兴趣,但风格原因也很受欢迎。

注意 MethodB 有一个主要的技术缺陷(提示:在通用代码中)。

有帮助吗?

解决方案

嗯,一方面,getAsConst 必须 当“this”指针为 const 时调用,而不是当您想要接收 const 对象时调用。因此,与其他问题一样,它的命名也被巧妙地错误了。(当“this”是非常量时,您仍然可以调用它,但那既不在这里也不在那里。)

忽略这一点, getAsConst 不会为您带来任何好处,并且会给使用该接口的开发人员带来过度的负担。现在他必须确定他当前是否正在使用 const 变量,以及他获取的新对象是否需要为 const,而不是仅仅调用“get”并知道他正在获取所需的内容。之后,如果两个对象由于某些重构而变得非常量,他就必须关闭他的调用。

其他提示

C++ 应该能够在几乎所有情况下完美地应对方法 A。我一直用它,从来没有遇到过问题。

在我看来,方法B违反了OnceAndOnlyOnce。而且,现在您需要弄清楚是否正在处理 const 引用来编写第一次编译的代码。

我想这是一个风格上的问题 - 从技术上讲,它们都有效,但 MethodA 使编译器工作得更加困难。对我来说,这是一件好事。

就我个人而言,我更喜欢第一种方法,因为它可以使界面更加一致。另外,对我来说 getAsConst() 听起来和 getAsInt() 一样愚蠢。

另一方面,在返回非常量引用或指向类的数据成员的非常量指针之前,您确实应该三思而后行。这是邀请人们利用你们班级的内部运作,最好是隐藏起来。换句话说,它破坏了封装。我会使用 get() const 和 set(),并且仅在没有其他方法或确实有意义时才返回非常量引用,例如提供对数组元素的读/写访问权限或矩阵。

鉴于标准库设置的样式先例(即 begin() 和 begin() const 仅举一个示例),很明显方法 A 是正确的选择。我怀疑选择方法B的人是否理智。

因此,通常首选第一种样式。

不过,在我当前正在处理的代码库中,我们确实使用了第二种样式的变体,因为我们希望在 const 和非常量用法之间有很大的区别。

在我的具体示例中,我们有 getTessellation 和 getMutableTessellation。它是通过写时复制指针实现的。出于性能原因,我们希望尽可能使用 const 版本,因此我们使名称更短,并使用不同的名称,这样人们就不会在不打算写入时意外地产生副本。

虽然您的问题似乎只涉及一种方法,但我很乐意就风格提供意见。就我个人而言,出于风格原因,我更喜欢前者。大多数 IDE 都会为您弹出函数的类型签名。

我更喜欢第一个。当本质上做同样事情的两件事看起来相同时,它在代码中看起来更好。另外,你很少有一个非 const 对象但想调用 const 方法,所以这没什么大不了的(在最坏的情况下,你只需要一个 const_cast<>)。

第一个允许更改变量类型(无论是 const 或不),无需进一步修改代码。当然,这意味着不会通知开发人员这可能已偏离预期路径。因此,这实际上取决于您是否重视能够快速重构,或拥有额外的安全网。

第二个是与匈牙利表示法有关的东西,我个人是这样的 就像这样我会坚持 第一的 方法。

我不喜欢匈牙利表示法,因为它增加了我在编程中通常讨厌的冗余。这只是我的意见。

由于您隐藏了类的名称,因此这种风格思考的内容可能适用,也可能不适用:

告诉这两个对象 MethodA 和 MethodB“get”或“getAsConst”有意义吗?您会将“get”或“getAsConst”作为消息发送到任一对象吗?

在我看来,作为消息的发送者/方法的调用者, 是获得价值的人;因此,为了响应此“获取”消息,您将向 MethodA / MethodB 发送一些消息,其结果就是您需要获取的值。

例子:如果 MethodA 的调用者是 SOA 中的服务,并且 MethodA 是存储库,则在服务的 get_A() 内,调用 MethodA.find_A_by_criteria(...)。

我看到的 MethodB 的主要技术缺点是,当对其应用泛型代码时,我们必须加倍代码才能处理 const 和非 const 版本。例如:

假设 T 是一个可排序的对象(即,我们可以使用运算符 < 与 T 类型的对象进行比较),假设我们想要找到两个 MethodA 之间的最大值(分别为:两种方法B)。

对于方法A,我们需要编写的代码是:

template <typename T>
T & getMax(T & p_oLeft, T & p_oRight)
{
   if(p_oLeft.get() > p_oRight.get())
   {
      return p_oLeft ;
   }
   else
   {
      return p_oRight ;
   }
}

此代码适用于 T 类型的 const 对象和非常量对象:

// Ok
const MethodA oA_C0(), oA_C1() ;
const MethodA & oA_CResult = getMax(oA_C0, oA_C1) ;

// Ok again
MethodA oA_0(), oA_1() ;
MethodA & oA_Result = getMax(oA_0, oA_1) ;

当我们想要将这个简单的代码应用于遵循 MethodB 约定的内容时,问题就出现了:

// NOT Ok
const MethodB oB_C0(), oB_C1() ;
const MethodB & oB_CResult = getMax(oB_C0, oB_C1) ; // Won't compile

// Ok
MethodA oB_0(), oB_1() ;
MethodA & oB_Result = getMax(oB_0, oB_1) ;

为了让 MethodB 在 const 和非常量版本上都工作,我们必须都使用已经定义的 getMax,但添加以下版本的 getMax:

template <typename T>
const T & getMax(const T & p_oLeft, const T & p_oRight)
{
   if(p_oLeft.getAsConst() > p_oRight.getAsConst())
   {
      return p_oLeft ;
   }
   else
   {
      return p_oRight ;
   }
}

结论是,由于不信任编译器的常量使用,我们在创建两个泛型函数时给自己带来了负担,而实际上一个函数就足够了。

当然,如果有足够的偏执,第二个模板函数应该被称为 getMaxAsConst...因此,问题将通过所有代码自行传播......

:-p

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top