除了C++;Dave Abrahams和Chris Diggins的界面创意 我最近在我的公司继承了一个遗留仿真框架,它是在2000年早期编写的,主要作者是从C和FORTRAN向C++过渡。接口/实现架构遵循Dave Abrahams和Chris Diggins在以下两个地方提出的想法:
本文解释了用于允许该接口的技术 引用类型在提供匹配的任何类型上都是多态的 函数签名。除了C++;Dave Abrahams和Chris Diggins的界面创意 我最近在我的公司继承了一个遗留仿真框架,它是在2000年早期编写的,主要作者是从C和FORTRAN向C++过渡。接口/实现架构遵循Dave Abrahams和Chris Diggins在以下两个地方提出的想法:,c++,c++11,interface,architecture,implementation,C++,C++11,Interface,Architecture,Implementation,本文解释了用于允许该接口的技术 引用类型在提供匹配的任何类型上都是多态的 函数签名。 简介 我的上一篇文章,多态性 在没有规划的情况下,讨论了OOTL(面向对象模板 库)使用由BIL(Boost接口)实现的技术 库),它包含在OOTL版本0.1中。这 让很多人对引擎盖下发生的事情感到好奇 背景 BIL允许实现一组 与要引用的已声明接口的函数相匹配的函数 使用单一类型: class Dog { public: const char* MakeSound() { return "woo
简介
我的上一篇文章,多态性 在没有规划的情况下,讨论了OOTL(面向对象模板 库)使用由BIL(Boost接口)实现的技术 库),它包含在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年04月25日的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{
私人:
//转发声明
模板
结构函数;
公众:
//接口
模板
baz(T&x):_m_a&x),_m_T(&functions::table)
{}
intfoo(intx)
{return _m_t->foo(const_cast(_m_a),x);}
整型条(字符常量*x)
{return{mu_t->bar(const_cast({mu a),x);}
私人:
//baz接口的功能表类型
结构表类型
{
整数(*foo)(无效*,整数x);
整型(*bar)(空*,字符常量*);
};
//对于给定的引用类型T,为
//函数表和表的静态实例。
模板
结构函数
{
静态baz::table_类型const table;
静态intfoo(void*p,intx)
{return static_cast(p)->foo(x);}
静态整型条(void*p,char const*x)
{return static_cast(p)->bar(x);}
};
无效常数*\u m\u a;
表const*\u m\t;};
模板baz::表类型const baz::函数::表=
{
&baz::functions::foo,&baz::functions::bar
};
构造一些东西{
intfoo(intx){返回x+1;}
int-bar(char-const*s){return std::strlen(s);}
};
构造另一个_baz{
intfoo(intx){返回x-1;}
int-bar(char-const*s){return-std::strlen(s);}
};
int main(){
一些_bazf ;;
另一个_baz f2;
baz p=f;
标准::printf(“p.foo(3)=%d\n”,p.foo(3));
标准::printf(“p.bar('hi')=%d\n”,p.bar(“hi”);
p=f2;
标准::printf(“p.foo(3)=%d\n”,p.foo(3));
标准::printf(“p.bar('hi')=%d\n”,p.bar(“hi”);
}
关于代码
上面的代码手动定义了一个名为baz
的接口引用,
它可以引用提供与
baz::表中的函数指针
每个接口引用变量都存储指向其函数的指针
通过变量baz::_m_t
存储一个指向
对象位于baz::_m_a
代码的作用是为每个类生成一个静态函数表
传递给baz
的T
。这些静态函数表具有
baz::table_type
和被命名为baz::function::table
。尽管
只有一个名称,因为它是的静态模板变量
baz::function
,为每个
baz::函数
。换句话说,我们使用编译器生成
每个类接口对的函数表
编译时
摘要
所描述的技术,即使是复杂的,也是
仍然需要简化BIL的实施方式。比尔是
更为复杂,因为它还提供了对广泛应用程序的支持
一系列技术,如面向方面编程、委托、,
泛型编程等等。BIL还需要解决以下问题:
C++预处理器的某些局限性。我会在未来写更多
随着BIL的成熟,并正式发布到
公共领域。希望本文能够帮助解释
技术背后的理论,可以为您提供一些关于
接口引用类型
<> Pr>框架的架构在过去几年里一直为我们服务,但是由于我们最终拥有了比使用Red Hat默认的更安全的现代编译器,所以我想开始升级框架以使用现代C++。
是否有人有更好的方法来设计支持动态多态性的接口/实现体系结构?不确定这是否是您想要的:
// a baz "interface"
class baz {
private:
struct IWrapper
{
virtual ~IWrapper() = default;
virtual int foo(int) = 0;
virtual int bar(const char*) = 0;
};
template <typename T>
struct Wrapper : IWrapper
{
T& t;
Wrapper(T& t) : t(t) {}
int foo(int n) override { return t.foo(n); }
int bar(const char* s) override { return t.bar(s); }
};
std::unique_ptr<IWrapper> wrapper;
public:
// interface
template <class T>
baz(T& x) : wrapper(std::make_unique<Wrapper<T>>(x)) {}
int foo(int x) { return wrapper->foo(x); }
int bar(char const* x) { return wrapper->bar(x); }
};
//一个baz“接口”
类baz{
私人:
str
#include <iostream>
#include <functional>
class Dog {
public:
const char* MakeSound() { return "woof"; }
};
class Duck {
public:
const char* MakeSound() { return "quack"; }
};
struct IAnimal {
template<class T>
IAnimal(T& t) : MakeSound{ [&t]{return t.MakeSound();}}
{}
std::function<const char*()> MakeSound;
};
int main() {
Dog dog;
Duck duck;
IAnimal animal = dog;
std::cout << animal.MakeSound() << std::endl; // prints woof
animal = duck;
std::cout << animal.MakeSound() << std::endl; // prints quack
return 0;
};