非成员函数如何改进封装

Nav*_*K N 17 c++ function

我阅读了Scott Meyers 关于这个主题的文章,并对他所谈论的内容感到很困惑.我这里有3个问题.

问题1

为了详细说明,假设我写一个简单的vector<T>类等的方法push_back,insert和运营商[].如果我遵循Meyers的算法,我最终会得到所有非会员朋友的功能.我将有一个带有很少私有成员和许多非成员朋友函数的向量类.这是他在说什么?

问题2

我仍然不了解非成员函数如何改进封装.考虑一下迈耶斯文章中给出的代码.

class Point {
public:
   int getXValue() const; 
   int getYValue() const; 
   void setXValue(int newXValue);
   void setYValue(int newYValue);

private:
  ...                 // whatever...
};
Run Code Online (Sandbox Code Playgroud)

如果遵循他的算法,setXXXX方法应该是非成员.我的问题是如何增加封装?他还说

我们现在已经看到,衡量一个类中封装量的合理方法是计算在类的实现发生变化时可能会被破坏的函数数量.

直到我们在类实现发生变化时保持方法签名不变,没有客户端代码会被破坏并且封装得很好,对吧?这同样适用于非成员函数.那么非成员函数提供的优势是什么?

问题3

引用他的算法

else if (f needs type conversions
         on its left-most argument)
   {
   make f a non-member function;
   if (f needs access to non-public
       members of C)
      make f a friend of C;
   }
Run Code Online (Sandbox Code Playgroud)

他的意思是f需要在最左边的参数上进行类型转换?他还在文章中说了以下内容.

此外,我们现在看到"朋友功能违反封装"的共同主张并不完全正确.朋友不会违反封装,他们只是减少它 - 与成员函数完全相同.

这个和上面的算法是矛盾的吧?

Mik*_*our 17

问题1

在这种情况下,遵循Meyers的算法将为您提供成员函数:

  • 他们需要虚拟吗?没有.
  • 他们operator<<还是operator>>?没有.
  • 他们需要类型转换吗?没有.
  • 它们可以在公共接口方面实现吗?没有.
  • 所以让他们成员.

他的建议是只在他们真正需要的时候才能成为他们的朋友; 支持非会员非朋友而不是朋友.

问题2

SetXXXX功能需要访问类的内部(私有)表示,所以它们不能被非成员非好友; 所以,迈耶斯认为,他们应该是成员而不是朋友.

通过隐藏类的实现细节来实现封装; 您可以与私有实现分开定义公共接口.如果您随后发明了更好的实现,则可以在不更改公共接口的情况下进行更改,并且使用该类的任何代码都将继续工作.因此,Meyers的"可能被破坏的函数数量"计算成员和朋友函数(我们可以通过查看类定义轻松跟踪),但不是通过其公共接口使用该类的任何非成员非朋友函数.

问题3

这已得到回答.

从迈耶斯的建议中取消的重点是:

  • 设计类使其具有与其私有实现分离的干净,稳定的公共接口;
  • 只有在真正需要访问实现时才能成为函数成员或朋友;
  • 只有当他们不能成为会员时才能成为朋友.


Ash*_*ish 9

意义f需要在其上进行类型转换 - 最左边的arg如下:

考虑以下senario:

Class Integer 
{  
    private: 
       int num;
     public:
        int getNum( return num;)
        Integer(int n = 0) { num = n;}

    Integer(const Integer &rhs)) { num = rhs.num ;}
    Integer operator * (const Integer &rhs)
    {
         return Integer(num * rhs.num);
    }
}


int main()
{
    Integer i1(5);

    Integer i3 = i1 *  3; // valid 

    Integer i3 = 3 * i1 ; // error     
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码 i3 = i1 * 3相当于this->operator*(3)有效,因为3被隐式转换为Integer.

在后面i3 = 3 * i1 等效的情况下3.operator*(i1),根据规则当u重载操作符使用成员函数时,调用对象必须是同一个类.但这不是那个.

为了完成Integer i3 = 3 * i1工作,可以定义非成员函数,如下所示:

Integer operator * (const Integer &lhs , const Integer &rhs) // non-member function
    {

         return Integer(lhs.getNum() * rhs.getNum());

    }
Run Code Online (Sandbox Code Playgroud)

我想你会从这个例子中得到一个想法.....