Visual C++ 2015 引入更新的 C++ 特性到 Windows API

Visual C++ 2015 是 C++ 团队付出巨大努力将现代C++引入windows平台的成果。在最新的几个发行版本里,VC++已经逐步添加了现代C++语言以及库的特色,这些结合在一起会创造一个用于构建通用windows App和组件的绝对惊艳的开发环境。Visual C++2015建立在早期版本引入的惊人进步,提供了成熟的、支持大多数C++11特性以及C++ 2015子集的编译器。你或许会怀疑编译器支持的完整程度,公正地说,我认为他能支持大部分重要的语言特性,支持现代C++将会迎来windows 程序库开发一片新的天地。这才是关键。只要编译器支持一个高效优雅的库的开发环境,开发者就能构建伟大的app和组件。

这里我不会让你看一个枯燥的新特性列表,或者走马观花地看下它的功能,而是会带你浏览下一些传统情况下的复杂代码现在如何让人相当愉快书写。当然,这得益于成熟的Visual C++编译器。我将会向你展示windows的一些本质,在现在或将来API中实际上都是很重要的本质。

颇具讽刺意味的是,对于COM来说,C++已经足够现代了.是的,我在谈论组件对象模型(COM),多年以来,它一直是大多数Windows API的基石.同时,它也继续作为Windows运行时的基石.COM无可争辩的依附于C++的原始设计,借鉴了许多来自C++的二进制和语义约定,但是它从来都不够优雅.C++的部分内容被认为可移植性不够,如dynamic_cast,必须避免使用它,以采用可移植的解决方案,这使得C++的开发实现更具挑战性.近些年已经为C++开发者提供了许多解决方案,让COM变得更加可移植.C++/CX 语言拓展,可能是Visual C++团队到目前为止最具野心的.具有讽刺意味的是,这些提升标准C++支持的努力,已经将C++/CX弃之不顾了,也让语言拓展变得冗余.

为了证明这点,我会展示给你如何完整的用现代C++实现IUnknown和IInspectable接口.关于这两个接口没有什么现代的或吸引力的东西.IUnknown继续成为卓越API,如DirectX,的集中抽象.这些接口--IInspectable继承自IUnknown--位于Windows运行时的中心.我将展示给你如何不用任何语言拓展来实现它们,接口表或其它宏--只需要包含大量类型信息的高效和优雅的C++,就可以让编译器和开发者拥有,关于如何创建所需的,优异的人机对话.

主要的问题是, 如何列出  COM 或 Windows Runtime 类需要实现的接口, 而且要方便开发者使用, 和编译器访问. 比如, 列出所有可用类型, 以便编译器查询, 甚至枚举出相应的接口. 要是能实现这样的功能, 也许就能让编译器生成 IUnknown QueryInterface 甚至 IInspectable GetIids 方法的代码. 这两个方法才是问题的关键. 按照传统的观念, 唯一的解决办法涉及到语言扩展(language extensions), 万恶的宏定义, 以及一堆难以维护的代码.

两种方法的实现, 都用到类需要实现的接口. 可变参数模板( variadic template)是首选:

template <typename ... Interfaces> class __declspec(novtable) Implements : public Interfaces ... { };

__declspec(novtable)拓展属性可以防止构造函数和析构函数初始化抽象类的vfptr,这通常意味着减少大量的代码.实现类模板包括一个模板参数包,这使它成为一个可变模板.一个参数包即一个模板参数接受任意数目的模板参数变量.但是在这种情况下,我描述的模板参数将只会在编译时进行查询.接口将不会出现在函数的参数列表之中.

这些参数的一个使用已经显而易见.参数包拓展后成为公共基础类的参数列表.当然,我仍然有责任到最后实现这些虚函数,但是此刻我会描述一个实现任意数目接口的一个具体类:

class Hen : public Implements<IHen, IHen2> { };

因为参数包拓展为指定基础类的列表,所有它等同于下面我可能会写出的代码:

class Hen : public IHen, public IHen2 { };

用这种方式结构化实现类模板的美妙之处在于,我现在可以,在实现类模板中,写入各种样版实现代码,而Hen类的开发者则可以使用这种不唐突的抽象,同时大量忽略隐含的细节.

到目前为止,一切都很好.现在,我将考虑IUnknown的实现.我应该可以在实现类模板中完整的实现它,并提供编译器现在所拥有的类型信息.IUnknown提供了对于COM类非常重要的两种工具,就像氧气和水对于人类一样.第一个可能简单些的是引用计数,这也是COM对象跟踪它们生命周期的方式.COM规定一种侵入式的引用计数,它借助于每个对象,统计多少个外部引用存在,来负责管理自己的生命周期.这与智能指针,如C++ 11的shared_ptr类,的引用计数恰恰相反,智能指针对象并不知道它的共享关系.你可能会争论这两种方式的优缺点.但是,实际上COM的方法通常更高效,这也是COM的工作方式,你必须处理它.如果没有其它的,你很可能会同意这点,在shared_ptr里面包装一个COM接口会是一件极不友好的事情!

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/e72489af08f8fb85966939de82b5812b.html