在之前的博客文章中,我展示了如何使用概念在 C++ 中定义“接口”。例如,我可以指定一个类型应该有 has_next、next 和 reset 方法:
模板<类型名T > 概念 is_iterable = requires ( T v ) { {诉。 has_next ( ) } - > std :: convertible_to < bool > ; {诉。 next ( ) } - > std :: same_as < uint32_t > ; {诉。重置( ) } ; } ;
然后我可以定义一个函数模板,将一个概念作为参数:
template < is_iterable T > size_t count ( T & t ) { 吨。重置( ) ; size_t计数= 0 ; while ( t . has_next ( ) ) { 吨。下一个( ) ; 计数+ + ; } 返回计数; }
在那篇博文中,我声明我没有将继承作为一种策略来考虑。让我们这样做吧。我们可以定义一个泛型基类和对应的泛型函数:
类iter_base { 公众: 虚拟布尔has_next ( ) = 0 ; 虚拟uint32_t next ( ) = 0 ; 虚拟无效重置( ) = 0 ; 虚拟~ iter_base ( ) = default ; } ; size_t count_inheritance ( iter_base & t ) { 吨。重置( ) ; size_t计数= 0 ; while ( t . has_next ( ) ) { 吨。下一个( ) ; 计数+ + ; } 返回计数; }
我可以定义一个适合这两个功能的类,因为它满足继承条件,以及概念:
结构iterable_array : iter_base { std :: vector <uint32_t>数组{ } ; _ size_t索引= 0 ; void reset ( ) {索引= 0 ; } bool has_next ( ) {返回索引<数组。尺寸( ) ; } uint32_t 下一个( ) { 指数+ + ; 返回数组[索引- 1 ] ; } } ;
到目前为止,一切都很好。但是,如果a是iterable_array的一个实例,这两个表达式有什么区别呢?
- 计数(一) ,
- count_inheritance(a) 。
给定一个优化编译器,第一个函数 ( count(a) ) 可能会立即返回支持向量的大小。该功能几乎是免费的。
第二个函数 ( count_inheritance(a) ) 对iterable_array类型一无所知,因此它将天真地遍历内容,并且可能要贵数百倍。
原文: https://lemire.me/blog/2023/04/20/defining-interfaces-in-c-concepts-versus-inheritance/