什么时候/为什么要在课堂上私有化?

时间:2010-12-22 03:31:40

标签: c++ oop class-design private-methods

我什么时候应该创建一个函数private,为什么这是个好主意?

8 个答案:

答案 0 :(得分:25)

当你不需要其他对象或类来访问函数时,你应该创建一个函数private,当你从类中调用它时。

坚持最小特权原则,只允许访问绝对必要的变量/函数。任何不符合此标准的内容都应为private

答案 1 :(得分:20)

我通常会创建辅助函数private。但是什么是帮助似乎含糊不清。那么让我举个例子。假设你有以下课程Sample;它暴露了一些公共功能,其中一个就是DoWork()。该函数有一个参数。但它并不假设参数始终有效,因此 first 检查参数的有效性,在该函数的开头它有很多代码。像这样:

class Sample
{
   public:
      void DoWork(SomeClass param)
      {
               /*
                *lots of code related to validation of param
                */  

                //actual code that operates on the param 
                //and other member data IF the param is valid
      }
};

由于您编写了许多与验证param相关的代码,因此会使函数变得繁琐且难以阅读。因此,您决定将此验证代码移至函数IsValidParam(),然后从DoWork()调用此函数,将参数param传递给它。像这样:

class Sample
{
   public:
      void DoWork(SomeClass param)
      {       
            if ( IsValidParam(param))       
            {
                //actual code that operates on the param 
                //and other member data IF the param is valid
            }
      }
};

那看起来更干净吧?

好的,你已经在课堂上的某个地方写过IsValidParam(),但你现在面临的问题是,你会使这个功能成为public吗?如果您的其他功能(例如DoWork())仅使用此功能 ,那么制作IsValidParam() public 就没有意义。所以你决定使用这个函数private

class Sample
{
   public:
      void DoWork(SomeClass param)
      {       
            if ( IsValidParam(param))       
            {
                //actual code that operates on the param 
                //and other member data IF the param is valid
            }
      }
  private:
      bool IsValidParam(SomeClass param)
      {
          //check the validity of param.
          //return true if valid, else false.
      }
};

此类函数(IsValidParam)应为private。我将这些函数称为辅助函数

希望这个解释可以帮助你!

答案 2 :(得分:5)

OOP的一个创始原则是封装。这是对象如何工作的功能保持在该对象的内部。这个想法是,如果代码不需要知道它是如何工作的,那么它就更容易使用它。有点像买微波炉 - 你只需要知道如何使用它而不是如何使用它。

应采用与OOP相同的方法。保留维护对象私有所需的一切。只使用完全使用公共对象所需的内容。

答案 3 :(得分:2)

如果您正在设计一个类 - 考虑到客户端代码应该使用它的方式 - 那么您将不可避免地派生出一个由publicprotected成员组成的接口。

private成员是支持和启用这些公共/受保护成员的功能和数据。 private函数应该考虑和/或模块化/构建非private成员所需的代码,使其实现更少冗余且更易于理解。

总而言之,如果成员private不打算由客户端代码直接使用,那么您就会成为成员private,并且仅存在以支持非{{1}}成员。

答案 4 :(得分:1)

你想成为纯粹主义者? :)

这个问题的正确答案与维持不变量有关。正确的做法是相当复杂的。

在基类中,您可以定义公共方法,以提供对类的访问的整个。所有这些方法都必须具体。这里的关键是假定公共不变量在调用这些函数之前和之后保持不变。这些函数绝不能互相调用,它们只调用受保护和私有方法。这些函数应该是公理的:它们应该是捕获所需语义所需的相当小的集合。

使用这些方法可以完成的大多数计算应该是全局的或至少是公共静态成员。

您还提供纯虚方法,这些方法是根据派生类中的表示来实现细节的钩子。基础中的虚拟功能应该是私有的。这里通常的建议(公开)是完全错误的。虚函数是实现细节。一个例外:虚拟析构函数必须是公共的。

私人助手功能也可以放在基地。

在基础中使用受保护的方法可能也很有用:这些方法将调用私有帮助程序或虚拟程序。如上所述:受保护的方法永远不应该调用protected或public方法。受保护的函数在每次调用之前和之后都保持比公共函数更弱的不变量。

私有函数通常保持非常弱的不变量。

这种严格的层次结构的原因是为了确保正确维护对象不变量。

现在,在派生类中,您提供了一个实现。理想情况下,这里的虚拟函数将是不可见,这是一种比仅仅私有更强的条件。在派生类中根本不应该调用这些虚函数。 唯一允许的访问权限是通过基础的受保护功能。

派生类的所有方法(包括析构函数)都应该是私有的。构造者必须是公开的,但他们不是班级的方法。

为了完全理解这些规则,您必须仔细考虑不变量。在调用公共方法之前,公共不变量可以假定持有,并且在完成后需要保存。因此,你不能从类内部调用这些函数,也不能从它派生任何类,因为这些函数用于修改公共函数的开始和结束之间的表示,因此不可避免地打破公共不变量:这就是为什么它们必须不要叫公共职能。

相同的参数适用于受保护的函数:函数只能调用具有较弱不变量的函数

公共从基类公共包装器调用虚函数,以确保打破公共不变量的操作顺序永远不会被破坏的不变量返回公共中断。虚拟集本身代表任何表示必须具有的不变结构。通过这样做,表示对公共客户端执行计算的所有操作都可以抽象到基础中。

在实践中,通常不遵循这些规则,因为它们通常会生成琐碎的包装器,并且需要编写和维护许多额外的代码。因此,虚拟功能通常最终会被公开,即使原则上这完全是完全错误的。

答案 5 :(得分:0)

在创建函数或类之前,我们应该了解该函数或类的范围,无论是全局还是本地。

例如:“ConnectionString()”。  每个数据库连接都需要“ConnectionString()”,因此它声明为Public。

答案 6 :(得分:0)

private:仅由此类使用,不被其他类使用,也不被派生类使用 protected:由此类使用,也可能是派生类,但不被其他类使用 public:由其他类,此类和派生类使用。

很难在私人和受保护之间做出选择。所以如果派生类有1%的可能需要它,我总是保护一个函数。

答案 7 :(得分:0)

我会在这里抛出一个反论点:不是使函数 private,它通常应该是 protectedvirtual。 以API调用或使用正常(即public函数没问题),但类的实现不足,或需要扩展的情况为例。 您将(当然)派生基类,并为您需要更改的公开 public 函数提供新定义。

第一个问题是派生类是否没有足够的访问内部变量或辅助函数来实现改进。即,要重写公开的 api 函数,没有辅助函数是不可能的。借用 Nawaz's excellent answer above,因为我将一些外部定义的类 SomeClass 作为参数传递给 public-ly 公开的 api void DoWork(SomeClass param),并使用辅助函数 bool IsValidParam(SomeClass param) 对其进行验证{1}},如果我需要重写DoWork,如果没有现有的辅助函数,比如IsValidParam,只能用protected来实现,那将会很痛苦。

第二个问题是您是否更愿意覆盖内部函数,而不是重新实现整个面向公众的调用函数。在这种情况下,您可以声明您的内部辅助函数 virtualSee also When to use Private Virtual。像上面的例子一样,如果我改变了 SomeClass,或者一个派生的,或者在不同的上下文下需要不同的(更严格的?更宽松的?)验证,我可能只覆盖 virtual IsValidParam,而保留 {{1} } 单独发挥作用。一般来说,如果您可能继承一个类,或将其用作基类,it's better to make it's functions virtual anyway

根据软件的性质或架构的设计,在早期阶段声明所有函数 DoWork 或/然后 public virtual 可能很有用,因为您限制了公开的 api .最后,根据需要拉出 protected virtual 或声明它 virtual。虽然不受限制,但它使下游改进更容易;特别是如果它减少了编辑已经“固定”或难以更改的库的需要。