代码之家  ›  专栏  ›  技术社区  ›  AndreasT

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

  •  39
  • AndreasT  · 技术社区  · 15 年前

    我必须就泛化和多态性做出决定。

    好吧,情况是标准的:我想让我的整体相互依赖 代码要更模块化、干净和可扩展。 目前仍处于设计原则变更可行的阶段, 而且,在我看来,非常有吸引力。

    我将介绍纯虚拟基类(接口)还是模板?

    我了解有关模板选项的基本信息: 更少的间接性,更好的性能,更多的编译 但是 没有后期绑定,等等。

    STL使用不多(或不使用?)继承权和提升权也没有。 但我认为这些工具的目标是成为一个非常小的基本工具, 由程序员编写的两行代码。

    我认为继承和后期绑定方法对于 插件式的大型代码和功能,应该是可互换的, 可更新等。在部署后,甚至在运行时。

    好吧,我的设想有点介于两者之间。

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

    这让我倾向于模板解决方案。 对我来说,它看起来也比较干净。

    有什么大的不好的暗示吗?接口还是这样吗? 外带?他们什么时候不在? 更符合标准C++风格?

    我知道这近乎主观,但我对 一些经验。我没有Scott Meyers有效C++的拷贝 所以我把希望寄托在你们身上:)

    6 回复  |  直到 8 年前
        1
  •  23
  •   Stack Overflow is garbage    15 年前

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

    模板唯一的潜在缺点是1)它们通常必须在头文件中定义(这意味着要包含更多的代码),这通常会导致编译速度变慢。

    但从设计角度看,如果可能的话,我看不到使用模板的任何问题。

    更符合标准C++ 风格?

    取决于什么是“标准C++风格”。C++标准库使用了所有的一部分。STL为所有内容使用模板,稍微旧一点的iostreams库使用继承和虚拟函数,当然,从C继承的库函数两者都不使用。

    现在,模板是最流行的选择,但是我不得不说这是最“标准”的方法。

        2
  •  10
  •   sbi    8 年前

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

    • 对象在运行时绑定;这更为灵活,但在运行时也会消耗更多的资源(CPU)
    • 强类型可以带来更多的类型安全性,但是需要 dynamic_cast (它有可能炸到顾客的脸上)可能很容易弥补这一点。
    • 可能更广为人知,也更容易理解,但“经典”的深层继承等级制度对我来说似乎是可怕的。

    按模板列出的编译时多态性的属性:

    • 编译时绑定允许更积极的优化,但会妨碍运行时的灵活性
    • duck类型可能看起来更尴尬,但失败通常是编译时失败。
    • 有时很难阅读和理解;没有概念,编译器诊断有时会变得愤怒。

    请注意,没有必要为任何一个做出决定。你可以自由地混合和混合它们(以及许多其他的习语和范例)。通常,这会导致非常令人印象深刻(和富有表现力)的代码。(例如,例如,类型擦除之类的东西)通过巧妙地混合范例来了解什么是可能的,你可能想浏览Alexandrescu的“现代C++设计”。

        3
  •  8
  •   Daniel Earwicker    15 年前

    这是一种虚假的反对。是的,继承和虚拟函数的主要用途是 iostreams 这是非常古老的,并且写的风格与其他 std 图书馆。

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

    boost::any std::tr1::function (以前也来自Boost)就是很好的例子。

    它们都是单个项目容器,具体类型在编译时未知(这在 any ,因为它有自己的类型的动态强制转换运算符来获取值)。

        4
  •  4
  •   AndreasT    14 年前

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

    • 可读性:括号太多,非语言强制(因此使用不当)约定太多
    • 对于正在经历编程语言常规演变的人来说,模板是不可读和不可理解的(只需看看boost bgl)
    • 有时感觉有人试图在AWK中编写C++代码生成器。
    • 编译器错误消息是cl(utter)ed垃圾
    • 太多的黑客需要(大多数在C++0X中补救)以获得一些基本的“语言”,比如功能。
    • 实现文件中没有模板,导致只包含头的库(这是一把非常双面的剑)
    • 通常,IDE的代码完成功能对模板没有太大帮助。
    • 在MPL中做大事似乎“讨价还价”,找不到另一个词来形容它。每行模板化代码都会在该模板类型上生成约束,这些约束以文本替换的方式强制执行。继承层次结构中存在固有的语义,模板结构中没有任何语义。就像一切都是空的一样,编译器试图告诉你是否会出现segfault。

    尽管如此,我还是在基本的实用程序和库中成功地使用了它。用它编写高级功能或与硬件相关的东西,对我来说似乎并没有什么好处。 也就是说,我用模板搭建积木,但用经典的方式建造房子。

        5
  •  0
  •   iain    15 年前

    在我看来,这是你最擅长的。如果你对OO有更多的经验,使用OO。如果你对仿制药有更多的经验,那就使用仿制药。

    这两种技术都有一些等价的模式,这意味着你可以使用它们中的任何一种。例如,OO中的策略与泛型中的策略,或OO中的模板方法与泛型中常见的循环模板模式。

    如果您计划重构已经工作但结构有点臭的生产代码。不要用它作为一个借口来使用一些新的设计技术,因为在一两年内,一旦你更好地理解了这种技术,你可能会后悔如何重构代码。当你学习技术时,很容易引入新的不灵活。其目的是改进现有代码的设计,如果你不擅长某项技术,你怎么知道你在改进设计,而不是在代码中构建一个巨大的阳具符号。

    就我个人而言,我更擅长OO,并且倾向于喜欢它,因为我知道我可以制作出易于理解且大多数人都可以改变的干净设计。大多数通用代码i的正确目的是与其他通用代码接口,例如编写迭代器或算法的通用函数。

        6
  •  0
  •   miked    14 年前

    我在我的大型代码库中都使用这两种代码。当类型在编译时已知时,我使用模板设计它;当它仅在运行时已知时,我使用虚拟函数。我发现虚拟函数更容易编程,以后更容易阅读,但是有时性能非常关键,而且模板化多态性(如果您真的可以称之为多态性)可以内联这一事实确实有帮助。