c ++标准实践:虚拟接口类与模板

And*_*asT 41 c++ polymorphism templates coding-style

我必须做出关于泛化与多态的决定.

那个场景是标准的:我想让我的单片相互依赖的代码更加模块化,干净和可扩展.它仍然处于可以改变设计原则的阶段,而且,正如我所看到的那样,非常需要.

我会介绍纯虚基类(接口)或模板吗?

我知道有关模板选项的基础知识:更少的间接性,更好的性能,更多的编译但没有后期绑定,等等.

stl不使用太多(或没有?)继承,而boost也没有.但我认为这些都是程序员每2行代码使用的非常小的基本工具.

我认为继承和后期绑定方法对于大部分代码和功能的插件样式更加明智,这些代码和功能在部署之后甚至在运行时期间应该是可互换的,可更新的等.

好吧,我的情景介于两者之间.

我不需要在运行时动态交换代码片段,编译时间很好.通常它也是一个非常核心且经常使用的功能,它在逻辑上不能分成大块.

这让我倾向于模板解决方案.对我来说它看起来也更清洁.

是否有任何重大的不良影响,接口仍然是要走的路?他们什么时候不是?哪个更符合标准的c ++风格?

我知道这接近于主观,但我对一些经历非常感兴趣.我没有Scott Meyers有效C++的副本,所以我寄希望于你们:)

jal*_*alf 25

你基本上是对的,当允许在运行时改变类型时(例如在插件架构中),动态多态(继承,虚拟)通常是正确的选择.如果类型只应在编译时更改,则静态多态(模板)是更好的选择.

模板的唯一潜在缺点是:1)它们通常必须在头文件中定义(这意味着更多代码会被#included),这通常会导致编译时间变慢.

但在设计方面,我无法在可能的情况下使用模板时遇到任何问题.

哪个更符合标准的c ++风格?

取决于"标准C++风格".C++标准库使用了一切.STL使用模板来处理所有事情,稍微旧的IOStreams库使用继承和虚函数,当然,从C继承的库函数也不使用.

目前,模板是迄今为止最受欢迎的选择,我不得不说这是最"标准"的方法.

  • "你唯一可以通过寻找关于它的文档" - 或者通过尝试编译并查看编译器抱怨无法找到的函数,是的.此外,Concepts旨在解决此问题.(即使它是一个接口,你仍然需要找到合适的文档.知道要覆盖哪些函数是不够的.你还需要知道它们的语义应该是什么,并且界面不会告诉你) .不过,你是对的.语言支持这两者是有原因的.:) (6认同)
  • 我确实看到使用模板而不是接口的一个问题:需求是完全隐含的.当您必须实现纯虚函数时,您将获得其确切的签名.但是当你看到像_AllocT或Iter这样的模板类型时,你不知道你的类需要具备什么,也不知道它是否必须是一个类.你唯一知道的方法是找一个关于它的合适的文档,我今天在尝试创建自己的stl兼容的分配器类时遇到了麻烦. (3认同)

sbi*_*sbi 11

经典面向对象多态的属性:

  • 对象在运行时绑定; 这更灵活,但在运行时也消耗更多资源(CPU)
  • 强大的打字带来了更多的类型安全性,但是dynamic_cast(以及它可能会炸成客户的脸)的需要可能很容易弥补
  • 可能更广为人知和理解,但"经典"的深层继承等级对我来说似乎很可怕

模板的编译时多态性的属性:

  • 编译时绑定允许更积极的优化,但可以防止运行时灵活性
  • 鸭子打字可能看起来更尴尬,但失败通常是编译时失败
  • 有时可能更难阅读和理解; 没有概念,编译器诊断有时会变得激动

请注意,无需任何一个决定.你可以自由地混合和混合它们(以及许多其他习语和范例).通常,这会导致非常令人印象深刻(和富有表现力)的代码.(例如,请参阅类型擦除等内容.)为了通过巧妙地混合范例来了解可能的内容,您可能需要浏览Alexandrescu的"现代C++设计".

  • 你当然是对的.然而,我的意思是(并且措辞不佳),在运行时多态性中,您可以确定所获得的是某个接口的故意实现,而编译时多态的鸭子输入可能会接受任何意外匹配.怎么说这个更好? (2认同)

Dan*_*ker 8

这是一种虚假的反对意见.是的,继承和虚函数的主要用途是iostreams,它们非常陈旧,并且以与其他std库完全不同的样式编写.

但许多"最酷"的现代C++库(如boost)确实利用了运行时多态性,他们只是使用模板来使它更方便使用.

boost::anystd::tr1::function(以前也来自提升)是很好的例子.

它们都是单项容器,其具体类型在编译时是未知的(这一点尤为明显any,因为它有自己的动态转换运算符来获取值).


And*_*asT 5

在我的盘子上积累了更多经验之后,模板中有一些我不喜欢的东西: 某些缺点使模板元编程无法成为一种可用的语言:

  • 可读性:太多括号,太多非语言强制(因此被误用)的约定
  • 对于正在经历编程语言通常演变的人来说,模板是不可读和不可理解的(看看 boost bgl)
  • 有时感觉就像有人试图用 awk 编写一个 c++ 代码生成器。
  • 编译器错误消息是 cl(utter)ed 废话
  • 为了获得一些基本的“语言”之类的功能,需要太多的 hacks(其中大部分在 c++0x 中修复)。
  • 实现文件中没有模板导致只有头文件的库(这是一把非常两面的剑)
  • 通常 IDE 的代码完成功能对模板没有太大帮助。
  • 在 MPL 中做大​​事似乎“讨价还价”,找不到其他词来形容。每一行模板化代码都会对该模板类型产生约束,这些约束以文本替换的方式强制执行。继承层次结构中有固有的语义,模板结构中没有。就像一切都是空的*,编译器试图告诉你是否会有段错误。

尽管如此,我在基本实用程序和库中非常成功地使用了它。用它编写高级功能或硬件相关的东西,对我来说似乎并不合适。这意味着我模板化了我的积木,但以经典的方式建造了房子。