2009-07-22 85 views
33

我必须做出关于泛化与多态的决定。C++标准做法:虚拟接口类与模板

那么这个场景是标准的:我想让我的单片互相依赖的 代码更模块化,干净和可扩展。 它仍处于设计原则的变化可行的阶段,我认为它非常可取。

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

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

STL的没有多大用处(或没有?)继承和升压的确不会。 但我认为这些都是真正的小型基本工具,程序员每使用这两行代码。

我认为继承和后期绑定方法对于部署后甚至运行时可更新的代码和功能的大块代码和功能的插件风格更为合理。

那么我的情况是介于两者之间。

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

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

是否有任何大的不良影响,因此仍然接口的方式 去?他们什么时候不是? 哪些更符合标准C++风格?

我知道这是主观的接壤,但我在 一些经验很感兴趣。我没有Scott Meyers有效的C++ 的副本,所以我将我的希望寄托在你们身上:)

回答

20

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

到模板的唯一潜在的缺点是:1)它们通常具有在报头中定义(这意味着更多的代码被包含(#include)),并且这常常导致更慢的编译时间。

但是在设计方面,我无法在使用模板时发现任何问题。

哪个更符合标准C++ 样式?

要看什么 “标准C++风格” 是。 C++标准库使用了一切。STL为所有事物使用模板,稍微陈旧的IOStreams库使用继承和虚函数,当然,从C继承的库函数也不使用。

这些天,模板是迄今为止最流行的选择,但我不得不说这是最“标准”的方法。

+3

嗯,我确实看到使用模板而不是接口的一个问题:需求是完全隐含的。当你必须实现纯虚函数时,你会得到它的确切签名。但是当你看到像_AllocT或Iter这样的模板类型时,你不知道你的类需要什么类型,甚至不需要是类。你唯一需要知道的方法是寻找一份关于它的体面文档,我今天尝试创建自己的stl兼容分配器类时遇到了麻烦。 – Virus721 2015-06-11 15:23:51

+3

“你只有通过寻找一个体面的文档来了解它” - 或者通过编译和查看编译器抱怨无法找到哪些函数,是的。此外,概念旨在解决这个问题。 (即使它是一个界面,你仍然需要找到体面的文档。知道要覆盖哪些函数是不够的。你还需要知道它们的语义应该是什么,并且界面不会告诉你)。尽管如此,你是对的。语言支持这两个原因是有原因的。 :) – jalf 2015-06-11 15:27:27

8

这是一种虚假的反对意见。是的,继承和虚拟功能的主要用途是iostreams,这是非常古老的,并与其他std库的风格非常不同。

但许多“最酷”的现代C++库(如boost)都使用运行时多态,它们只是使用模板来使它更方便使用。

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

它们都是单项容器,它的具体类型在编译时是未知的(这在any中尤其明显,因为它有自己的一种动态转换运算符来获取值)。经典的面向对象的多态性

+0

+1您的回答非常有启发性,但遵守问题我接受了贾尔夫的建议。谢谢。 – AndreasT 2009-08-24 13:54:50

9

性质:

  • 对象在运行时约束;这是更灵活的,但也消耗更多的资源(CPU)在运行时
  • 强打字带来更多的类型安全,但需要dynamic_cast(和它的潜力吹到客户的脸上)可能很容易弥补
  • 可能更广泛地了解和理解,但“经典”深继承层次看起来可怕我编译时多态性

属性的模板:

  • 编译时绑定允许更积极optimizat但会妨碍运行时的灵活性
  • 鸭式打字看起来似乎更笨拙,但失败通常是编译时失败
  • 有时可能难以阅读和理解;没有概念,编译器诊断有时可能变得令人生气

请注意,没有必要为任何一个决定。你可以自由地混合和混合他们(和许多其他成语和范例)。通常,这会导致非常令人印象深刻的(和富有表现力的)代码。 (例如,请参阅类型擦除的内容。)要想知道通过巧妙地混合范例有什么可能,您可能需要浏览Alexandrescu的“Modern C++ Design”。

0

从我的角度来看,这是你最擅长的。如果您有更多面向对象使用面向对象的经验。如果您有更多关于泛型的经验,请使用泛型。

这两种技术都有一些等同的模式,这些模式也意味着你可以使用很多东西。 EG战略OO与泛型中的策略或OO中的模板方法与泛型中常见的循环模板模式。

如果您计划的重构生产代码已经正常工作,但结构有点臭。不要以此为借口来使用一些新的设计技术,因为在一两年后,如果您更好地理解技术,您可能会后悔如何重构代码。在学习技巧时,引入新的不灵活性非常容易。如果你不熟练使用某种技术,则目的是改进现有代码的设计。你如何知道自己正在改进设计,而不是在代码中构建一个大的阴茎符号。

就我个人而言,我在OO方面更好,并倾向于支持它,因为我知道我可以制作易于理解且大多数人可以改变的干净设计。大多数通用代码我正确的目标是与其他通用代码进行交互,例如编写迭代器或用于算法的通用函数。

4

已经铲了我的盘子里一点经验后,有模板一些事情,我不喜欢: 有迹象表明,从一个可用的语言资格模板元编程一定的缺点:

  • 可读性:太多的括号,太多的非语言的执行(因此滥用)公约
  • 的人经历的编程语言通常的进化,模板是不可读UND难以理解(只看提升BGL)
  • 有时感觉就像是有人试图到w在awk中成为一个C++代码生成器。
  • 编译器错误消息是cl(完全)ed废话
  • 需要太多的hacks(其中大多数补救在C++ 0x)以获得一些基本的“语言”功能。
  • 否实现文件中的模板导致仅标头库(这是一个双面剑)
  • 通常IDE的代码完成功能对模板没有多大帮助。
  • 在MPL中做大事似乎“讨厌”,找不到别的词。模板化代码的每一行都会对该模板类型产生约束,这些约束将以文本替换方式强制执行。继承层次结构中存在固有的语义,模板结构中没有任何内容。就像所有东西都是void *一样,编译器试图告诉你是否会出现段错误。

就这么说,我在基本实用程序和库上使用它非常成功。用它编写高级功能或硬件相关的东西,似乎并不适合我。 含义我模板我的积木,但建立房子的经典方式。

0

我在我的大代码库中都使用这两个函数。在编译时知道类型时,我使用模板进行设计,只有在运行时才知道类型,我使用虚函数。我发现虚拟函数更容易编程,并且稍后可以更容易阅读,但有时候性能是至关重要的,而模板化的多态性(如果你真的可以称之为多态性)可以内联的真正帮助。