我最近继承了我公司的旧版模拟框架,该框架是在2000年代初期编写的,当时主要作者正在从C&Fortran过渡到C ++。接口/实现体系结构遵循Dave Abrahams和Chris Diggins在这两个地方的想法:
本文介绍了允许界面使用的技术引用类型在提供匹配的任何类型上都是多态的功能签名。简介
背景
BIL允许任何实现一组与已声明接口匹配的函数,将被引用使用单一类型:class Dog { public: const char* MakeSound() { return "woof"; } }; class Duck { public: const char* MakeSound() { return "quack"; } }; BOOST_IDL_BEGIN(IAnimal) BOOST_IDL_FXN0(MakeSound, const char*) BOOST_IDL_END(IAnimal) int main() { Dog dog; Duck duck; IAnimal animal = dog; puts(animal.MakeSound()); // prints woof animal = duck; puts(animal.MakeSound()); // prints quack return 0; };
问题我经常被问到,实际上我们怎么能静态地拥有C ++中的类型化接口,而无需在对象?
双倍宽度指针
为了实现任何一种动态分派,我们需要在代码中的某个地方进行函数表查找,否则我们将无法拥有运行时多态性。的然后在内部将接口引用表示为双倍宽度指针;一个指针指向该对象,而另一个指针指向指向功能表。该功能表是静态创建的在编译时使用模板。为每个类到接口的类型转换创建一个功能表编码。这是使用分配的模板版本完成的运算符和初始化构造函数。
手动创建接口参考类型
Boost-Consulting.com的Dave Abrahams将以下代码发布到2004年4月25日的comp.std.c ++是对我原来的版本的改进方案,以及接口代码生成工具使用的技术HeronFront。上面的代码手动定义了一个名为// a baz "interface" class baz { private: // forward declarations template <class T> struct functions; public: // interface template <class T> baz(T& x) : _m_a(&x), _m_t(&functions<T>::table) {} int foo(int x) { return _m_t->foo(const_cast<void*>(_m_a), x); } int bar(char const* x) { return _m_t->bar(const_cast<void*>(_m_a), x); } private: // Function table type for the baz interface struct table_type { int (*foo)(void*, int x); int (*bar)(void*, char const*); }; // For a given referenced type T, generates functions for the // function table and a static instance of the table. template <class T> struct functions { static baz::table_type const table; static int foo(void* p, int x) { return static_cast<T*>(p)->foo(x); } static int bar(void* p, char const* x) { return static_cast<T*>(p)->bar(x); } }; void const* _m_a; table const* _m_t; }; template <class T> baz::table_type const baz::functions<T>::table = { &baz::functions<T>::foo , &baz::functions<T>::bar }; struct some_baz { int foo(int x) { return x + 1; } int bar(char const* s) { return std::strlen(s); } }; struct another_baz { int foo(int x) { return x - 1; } int bar(char const* s) { return -std::strlen(s); } }; int main() { some_baz f; another_baz f2; baz p = f; std::printf("p.foo(3) = %d\n", p.foo(3)); std::printf("p.bar('hi') = %d\n", p.bar("hi")); p = f2; std::printf("p.foo(3) = %d\n", p.foo(3)); std::printf("p.bar('hi') = %d\n", p.bar("hi")); }
关于代码
baz
的接口引用,可以引用任何提供与baz::table
中的函数指针。每个接口引用变量都存储一个指向其功能的指针表通过变量baz::_m_t
并存储指向baz::_m_a
中的对象。
代码的作用是为每个类生成一个静态函数表T
传递给baz
。这些静态功能表的类型为baz::table_type
并命名为baz::function<T>::table
。即使只有一个名称,因为它是一个静态模板变量baz::function
,为的每个实例创建一个单独的baz::function
。换句话说,我们使用编译器生成每个类的功能表-接口对的可能性编译时。
摘要
所描述的技术,即使它是复杂的,也是仍然简化了BIL的实现方式。 BIL是复杂得多,因为它还提供了广泛的支持各种技术,例如面向方面的编程,委托,通用编程等。还需要BIL解决C ++预处理程序的某些限制。我会在随着BIL的成熟,它的未来,并正式发布到公共领域。希望本文确实有助于解释技术背后的理论,可以为您提供一些深入的了解接口引用类型。框架的体系结构多年来为我们提供了很好的服务,但是由于我们终于拥有了所有安全性文件,可以使用比Red Hat默认包含的现代编译器更多的现代编译器,因此我想开始将框架升级为使用现代C ++。
有人能设计出支持动态多态性的接口/实现体系结构的更好方法吗?
我最近继承了我公司的旧版模拟框架,该框架是在2000年代初期编写的,当时主要作者正在从C&Fortran过渡到C ++。接口/实现...
不确定是否是您想要的: