为什么我们需要将私有成员放在标题中?


62

私有变量是一种向类用户隐藏复杂性和实现细节的方法。这是一个相当不错的功能。但是我不明白为什么在c ++中我们需要将它们放在类的标题中。我看到这有两个令人讨厌的缺点:

  • 它使用户的标题杂乱无章
  • 每当修改内部结构时,它将强制重新编译所有客户端库

此要求背后是否存在概念上的原因?仅仅是为了简化编译器的工作吗?


您可以在标头中声明一个空结构,但随后只能在使用该结构时使用指向该结构的指针(并且不能分配一个)
棘手怪胎

3
@ratchetfreak:否,struct foo{};不允许为空(),但可以使用前向声明(struct foo;)。
MSalters 2012年

@MSalters就是我的意思
棘轮怪胎

1
让我补充一点缺点:*在.h文件中编写私有函数头是浪费大量时间。(暂时忘记朋友课程)
Jonny

Answers:


68

这是因为C ++编译器必须知道该类的实际大小,才能在实例化时分配适当的内存量。人数包括所有成员,也包括私人成员。

避免这种情况的一种方法是使用Pimpl惯用语,Herb Sutter在他的每周大师系列#24#28中对此进行了解释。

更新资料

确实,这(或更普遍地说,头文件/源文件的区别和#includes)是从C继承的C ++中的一个主要障碍。在创建C ++ C的年代,还没有大规模软件开发的经验。开始引起真正的问题。从那以后,所学到的教训被较新的语言的设计师所听取,但是C ++受向后兼容性要求的束缚,这使得真正解决语言中的这一基本问题变得非常困难。


这种信息不是仅包含在类库中吗?它用于链接吗?
西蒙·贝格

@Simon,“类库”是什么意思?
彼得Török

我的意思是包含类定义和方法的目标文件的集合
Simon Bergot,2012年

7
创建C ++时,AT&T / Bell Labs(当时是Stroustrups的雇主)当然具有大规模C开发的经验。他们的5ESS电话交换软件当时可能是世界上最大的单个C程序。关于OO的早期想法已经在该代码库中可见,并且Cfront模仿了这些技术。但是,的概念private更为现代。
MSalters

1
在C语言中,您只需将分配器放入库函数中即可;客户将根本无法分配这样的结构。这会增加一些开销,但使在各个版本之间迁移代码变得微不足道,因此这通常是值得的。但是,它的确会导致代码风格与C ++截然不同。
Donal研究员2012年

15

无论您在何处使用了类的对象,类定义都必须足以使编译器在内存中产生相同的布局。例如,给出如下所示:

class X { 
    int a;
public:
    int b;
};

编译器的a偏移量通常为0,b偏移量为4。如果编译器认为这仅仅是:

class X { 
public:
    int b;
};

它将“认为” b应该在偏移量0而不是偏移量4处。当将使用该定义的b代码分配给时,使用第一个定义的代码将a被修改,反之亦然。

最小化对类的私有部分进行更改的影响的通常方法通常称为pimpl习惯用语(我相信Google可以为它提供大量信息)。


1
我在问一个设计决定。当然,您需要将私有成员声明放在某个位置,以便该语言起作用。但是,为什么要在标题中而不是在更私密的地方呢?
西蒙·贝格

7
@Simon:标头是编译器看到的所有内容,用于告诉它类/结构的外观。已经讨论过将类似模块的内容添加到C ++中的做法,这些方法会更多地隐藏这种数据,但是到目前为止,该数据尚未得到批准(尽管也没有完全删除)。
杰里·科芬

3
不过,一个简单的规则是最后分配此类“ .cpp定义”的私有成员。这意味着公共和“正常”私人成员的抵消额将不依赖于它们。IMO的真正原因是您不能从此类继承,因为派生部分甚至必须跟随那些私有成员。
MSalters 2012年

3

最有可能是几个原因。尽管大多数其他类都无法访问私有成员,但朋友类仍然可以访问它们。因此,至少在这种情况下,标头中可能需要它们,以便朋友类可以看到它们的存在。

依赖文件的重新编译可能取决于您的包含结构。在某些情况下,将.h文件而不是其他头文件包含在.cpp文件中可以防止重新编译的时间过长。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.