为什么界面中定义了私有成员/方法?

时间:2011-09-08 06:35:46

标签: c++ oop

我一直对以下事实感到困惑:大多数OOP语言(或者更确切地说,C ++)使您在界面中定义私有方法/成员(通过接口我的意思是类声明 - 似乎我感到困惑)。这不是显示类的实现细节,而是违背封装的想法吗?

这是否有充分理由让我失踪?

6 个答案:

答案 0 :(得分:12)

对于C ++来说,这是一个实现问题。

C ++编译器必须能够通过仅查看类声明而不是实现来生成使用类的代码。编译器需要的一个非常重要的事情是类的实例的大小,因为C ++通过嵌入而不是通过存储对单独对象的引用来处理对象中的子对象。为了能够构建对象(例如struct X { Y y; Z z; }),必须事先知道所有子对象(例如YZ)的大小。

此问题的解决方法是使用the "pimpl" pattern (also named the "compiler firewall" pattern),允许您将所有内部详细信息隐藏在类的用户之外。不幸的是,它带来了一些运行时的额外成本,但大部分时间它都可以忽略不计。使用这种方法,公共对象将始终具有指针的大小,并且将使用额外的间接访问实例中的所有数据...优点是您可以添加私有数据成员,并且该类的用户不需要重新编译(例如,如果您的类在DLL中,则允许保持二进制兼容性。)

能够在实现部分中声明私有方法(没有数据)是可能的,而编译器没有任何增加的复杂性,但C ++设计者认为最好为类保留一个单独的声明。

实际上,即使只是添加私有方法也可能会影响许多实现中类实例的大小(例如,如果私有方法是类中唯一的虚方法)。

答案 1 :(得分:8)

C ++是我所知道的唯一能够做到这一点的语言;值得注意的是,有几种功能语言严格区分公共和私有接口的声明。请注意,C ++在声明定义之间有所不同:您只需要在接口中声明私有函数,而不是 define < / em>他们。

对于成员变量和虚函数,有一个简单的技术原因:它们会影响类的物理布局。由于这种布局在翻译单元之间需要相同,因此所有单元都需要知道布局 - 因此需要知道课堂的实际构成。

我怀疑您还需要在C ++中公开声明非虚函数以保持其一致性:否则,您必须在不同的地方声明不同的函数,具体取决于它们是否是公共的和/或虚拟的

可以通过使用handle-body idiom(也称为美容不太吸引人的名字“PIMPL”)来规避这一限制,但这会增加解决方案的复杂性。

答案 2 :(得分:2)

有两种含义,其中在C ++中使用了单词interface:OOP接口和类型声明。

OOP接口用于封装和多态。在C ++中,它通常用纯抽象类实现。 PIMPL成语也用于封装。在任何一种情况下,消费者只显示类型的公共成员,并通过间接层访问私有实现。 Java和C#支持显式接口,并且都将其成员限制为公共访问。

由于链接模型,C ++中需要类型声明。类型的声明不是它在OOP意义上的接口,但是因为在使用之前必须包含类型的声明,所以解耦实现变得更加可取。为了实现这一点,我们使用OOP接口,如上所述。如果只有C ++支持的模块,则不需要隐藏类型声明中的私有实现细节。 {C} 11提出Module support,但由于时间限制将被包含在未来的TR中。

答案 3 :(得分:2)

在C ++的特定情况下,一个原因是需要声明所有虚函数 - 无论是公共函数还是私有函数 - 以生成虚拟指针表。可能同样的原因也适用于其他语言。

这不违反封装的想法,私有方法/成员不是 PUBLIC 接口的一部分,因此数据仍然是封装的。此外,公共/私人修饰符仅强制执行可见性。

答案 4 :(得分:0)

在C ++中有很多技巧可以解决这个问题。

您可以使用factory pattern向用户隐藏私有成员和方法。 您需要创建一个abstract class作为您的API或接口,而不是在子类中实现您的类并在那里声明您的所有私有成员,这样您的用户就不会看到您的私有成员和实现。< / p>

答案 5 :(得分:-1)

你如何得出这样的结论?我发现没有OOP语言让我这样做。对于C ++,人们在界面中定义方法的原因是为了内联。对于会员来说,这是因为你无法在其他任何地方定义它,它适用于所有的可见性,而不仅仅是私人。