Dave Abrahams和Chris Diggins有什么现代替代C ++接口的思想

问题描述 投票:0回答:2

我最近继承了我公司的旧版模拟框架,该框架是在2000年代初期编写的,当时主要作者正在从C&Fortran过渡到C ++。接口/实现体系结构遵循Dave Abrahams和Chris Diggins在这两个地方的想法:

  1. http://groups.google.com/group/comp.std.c++/msg/85af30a61bf677e4
  2. https://www.codeproject.com/Articles/8896/Polymorphism-without-Planning-under-the-hood
  3. 本文介绍了允许界面使用的技术引用类型在提供匹配的任何类型上都是多态的功能签名。简介

我以前的文章,多态没有计划,讨论了OOTL(面向对象模板)库)使用BIL(增强接口)实现的技术OOTL发行版0.1中随附的库)。这个让很多人对引擎盖下发生的事情感到好奇。

背景

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 ++。接口/实现...

c++ c++11 interface architecture implementation
2个回答
1
投票

不确定是否是您想要的:


0
投票

模板构造器+ std :: function

© www.soinside.com 2019 - 2024. All rights reserved.