6

所以这就是我所知道的:

  • 明智的做法是不要直接在您的 API 中公开您的 ivars;而是使用访问器
  • const指向非对象的指针const仅意味着您可以更改对象,但不能重定向指针指向的位置

这是我的情况:

我有一些相关的课程。我想创建一个简单的类,通过composition将这些组合成一个逻辑接口。我的每个封闭类在其 API 中都已经有了公共和私有的区别,所以我不介意将它们直接暴露给我父类的用户。这意味着为这些 ivars 编写访问器对我来说太过分了,因为这些类已经管理了哪些是公共的,哪些不是。但是,我不希望用户更改包含在这个组合父类中的实际对象。

所以我能想到的唯一方法是使用const指向这些对象的指针,例如:

class Parent{

  public:

   EnclosedClass1*const ec1; //users can enjoy the public API of EnclosedClass
   EnclosedClass2*const ec2;

   void convenienceMethod(){
         //performs inter-related functions on both ec1 and ec2
    }

 }

这样,让某人直接与 API 交互并没有什么害处,ec1但是ec2,我想确保这是相当万无一失的,因为至少该人无法更改被操纵的实际资源,因此无法更改const指针。

这有意义吗,是不是很好地使用了 const 指针?

或者,我可以private完全制作它们,忘记指针(这个类无论如何管理这些对象),只做额外的工作来为这些对象中包含的公共函数编写访问器。但这似乎有点矫枉过正,对吧?

4

6 回答 6

6

The traditionnal OOP way is to keep data private, and have public accessors if one want to use them outside of the class.

If you don't want the private data pointers to be modified, then you don't provide setters, only the getters.

class Parent{

  private:
       EnclosedClass1*const ec1;
       EnclosedClass2*const ec2;

  public:
      EnclosedClass1* getEnclosedClass1() const {...};
      EnclosedClass2* getEnclosedClass2() const {...};    

      void convenienceMethod(){
    }

}

another possibility (like @pmr proposes in the comments below) is:

const EnclosedClass1& getEnclosedClass1() const {...};
const EnclosedClass2& getEnclosedClass2() const {...};    

with const reference you protect the user from testing the value returned by the getters. But you must ensure that your object state is consistent and never have internal pointers to nullptr; in such case you should throw an exception.

于 2013-05-06T12:15:28.180 回答
2

这种方法有不同的问题。第一个是成员在其接口上具有公共和私有方面这一事实,从封闭类型的角度来看并不意味着任何事情。完整类型可以有一组不同的不变量,用户可以通过独立修改两个子对象来打破这些不变量。

即使该Parent类型没有任何不变量(即它不依赖于子对象的状态),所提出的方法也不是 const 正确的。给定一个const Parent&调用者可以对两个子对象应用任何操作(const 和非 const),有效地改变Parent对象的状态。在这种情况下,更好的方法是直接存储子对象:

class Parent {
public:
   EnclosedClass1 ec1;
   EnclosedClass2 ec2;
...

但我建议您确实提供访问器来提取数据和突变器(如果这个词有意义的话)来改变对象的状态。这样,如果您稍后需要添加不变量,您可以将它们粘贴在那里。

于 2013-05-06T12:26:56.583 回答
1

这有意义吗?是的。

使用 const 指针好不好?嗯,不是真的。规范的编码方式是为每个元素设置一个 getter 函数并将内部数据设为私有。采用另一种方式会使您的代码的读者想知道您为什么要这样做,因为这不是标准做法。

因此,将您的 const 指针设为私有并创建 getter 来访问它们。出于性能原因,您可以将这些 getter 设为inlined 函数,这样不会对生成的可执行文件产生任何影响,但会大大提高代码的可读性。

于 2013-05-06T12:24:44.863 回答
0

原因之一可能是它可以通过 constcast 转换为非 const 指针。

于 2013-05-06T12:59:09.467 回答
0

决定你的类应该做什么,并编写一个提供这些东西的接口。如果允许用户弄乱内部数据很重要,那么编写接口来做到这一点。但是,在大多数情况下,一个类所呈现的抽象不同于您可以对其内部数据执行的操作的总和,因此接口不应暴露内部数据。例如,保存学生姓名的类通常会将其实现为某种保存std::string数据的容器。那堂课不应该为人名提供指向字符串的指针或引用。相反,例如,如果需要更正名称,则应在单独的编辑器类中完成;更正后,可以使用新版本更新存储的名称。类不需要std::string向用户公开整个界面。

于 2013-05-06T13:12:19.703 回答
0

If you have a class that contains two other objects and provides free and full access to those members to its clients, then you should think about whether your class has the right design. The law of demeter doesn't become invalid because you don't use a getter, i.e. parent.ec1->foo is no better than parent.getEc1().foo.

In any case, const members are generally more trouble than they're worth.

于 2013-05-06T12:18:20.813 回答