非会员非朋友功能与私人功能

Jar*_*red 14 c++ refactoring

Herb Sutter表示,在C++中编写方法的最面向对象的方法是使用非成员非友元函数.这是否意味着我应该采用私有方法并将它们变成非成员非朋友函数?这些方法可能需要的任何成员变量都可以作为参数传入.

示例(之前):

class Number {
 public:
  Number( int nNumber ) : m_nNumber( nNumber ) {}
  int CalculateDifference( int nNumber ) { return minus( nNumber ); }
 private:
  int minus( int nNumber ) { return m_nNumber - nNumber; }
  int m_nNumber;
};
Run Code Online (Sandbox Code Playgroud)

示例(后):

int minus( int nLhsNumber, int nRhsNumber ) { return nLhsNumber - nRhsNumber; }
class Number {
 public:
  Number( int nNumber ) : m_nNumber( nNumber ) {}
  int CalculateDifference( int nNumber ) { return minus( m_nNumber, nNumber ); }
 private:
  int m_nNumber;
};
Run Code Online (Sandbox Code Playgroud)

我是在正确的轨道上吗?是否应将所有私有方法移至非成员非朋友函数?什么应该是规则,否则会告诉你?

Dav*_*eas 17

我相信自由功能并同意Sutter,但我的理解是相反的.并不是说你的公共方法应该依赖于自由函数而不是私有方法,而是你可以使用提供的公共接口在类之外用自由函数构建更丰富的接口.

也就是说,你不要将你的私有部分推到类之外,而是将公共接口减少到最小,这允许你以尽可能少的耦合构建其余的功能:只使用公共接口.

在您的示例中,如果可以根据其他操作有效地表示,我将在类外部移动的是CalculateDifference方法.

class Number { // small simple interface: accessor to constant data, constructor
public:
  explicit Number( int nNumber ) : m_nNumber( nNumber ) {}
  int value() const { return m_nNumber; }
private:
  int m_nNumber;
};
Number operator+( Number const & lhs, Number const & rhs ) // Add addition to the interface
{
   return Number( lhs.value() + rhs.value() );
}
Number operator-( Number const & lhs, Number const & rhs ) // Add subtraction to the interface
{
   return Number( lhs.value() - rhs.value() );
}
Run Code Online (Sandbox Code Playgroud)

优点是,如果你决定重新定义你的数字内部(你可以用这么简单的类做的那么多),只要你保持公共接口不变,那么所有其他功能都可以开箱即用.内部实现细节不会强制您重新定义所有其他方法.

困难的部分(不是上面的简单示例)是确定您必须提供的最少接口.从上一个问题引用的文章(GotW#84)就是一个很好的例子.如果你仔细阅读它,你会发现在保持相同的功能和性能的同时,你可以大大减少std :: basic_string中的方法数量.计数将从103个成员函数下降到只有32个成员.这意味着类中的实现更改将仅影响32个而不是103个成员,并且由于保留了接口,因此不需要更改可以实现32个成员的其余功能的71个自由函数.

这一点非常重要:它更加封装,因为您限制了实现更改对代码的影响.

移出原始问题,这是一个简单的例子,说明如何使用自由函数改进类的更改的局部性.假设一个具有非常复杂的加法运算的复杂类.你可以去实现它并将所有运算符覆盖实现为成员函数,或者你可以在内部轻松有效地实现其中的一些,并将其余部分作为自由函数提供:

class ReallyComplex
{
public:
   ReallyComplex& operator+=( ReallyComplex const & rhs );
};
ReallyComplex operator+( ReallyComplex const & lhs, ReallyComplex const & rhs )
{
   ReallyComplex tmp( lhs );
   tmp += rhs;
   return tmp;
}
Run Code Online (Sandbox Code Playgroud)

可以很容易地看出,无论原作如何operator+=执行其任务,free 都能operator+正确执行其任务.现在,对于课程的任何和所有更改,operator+=都必须进行更新,但外部operator+将在其余生中保持不变.

上面的代码是一个常见的模式,虽然通常不是lhs通过常量引用接收操作数并在内部创建临时对象,但可以更改它以使参数本身成为值副本,从而帮助编译器进行一些优化:

ReallyComplex operator+( ReallyComplex lhs, ReallyComplex const & rhs )
{
   lhs += rhs;
   return lhs;
}
Run Code Online (Sandbox Code Playgroud)


Gab*_*yer 11

并非所有私有方法都应该移动到非成员非友元函数,但那些不需要访问私有数据成员的函数应该是.你应该尽可能少地访问,尽可能地封装你的类.

我强烈建议您阅读Scott Meyers的Effective C++,它解释了为什么要这样做以及何时适当.

编辑:我想补充说,对于私有方法然后对于公共方法来说这不太正确,尽管仍然有效.由于封装与您将通过修改方法而破解的代码量成比例,具有私有成员函数,即使它不需要访问数据成员.这是因为修改代码会破坏很少的代码,只会破坏你可以控制的代码.