- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我最近在我的公司继承了一个遗留的模拟框架,它是在 2000 年代初期编写的,当时主要作者正在从 C 和 Fortran 过渡到 C++。接口(interface)/实现架构遵循 Dave Abrahams 和 Chris Diggins 从以下两个地方提出的想法:
This article explains the techniques used to allow the interface reference types to be polymorphic on any type which provides matching function signatures.
Introduction
My previous article, Polymorphism without Planning, discussed how the OOTL (Object Oriented Template Library) uses a technique implemented by the BIL (Boost Interfaces Library) which is included with the OOTL release version 0.1. This left a lot of people curious about what was going on under the hood.Background
The BIL allows any object that implements a set of functions which match those of a declared interface, to be referred to using a single type: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;
};The question that I am asked frequently, is how in fact can we have statically typed interfaces in C++, without placing any extra information in the object?
Double-Width Pointers
In order to achieve any kind of dynamic dispatch, we require a function table lookup somewhere in our code, otherwise we wouldn't be able to have run-time polymorphism. The interface reference is then represented internally as a double width pointer; one pointer points to the object, while the other object points to a function table. This function table is created statically at compile-time using templates.A function table is created for every class-to-interface type-cast in the code. This is done using template versions of the assignment operator and initializing constructor.
Creating Interfaces Reference Types by Hand
Dave Abrahams of Boost-Consulting.com posted the following code to comp.std.c++ on 2004-04-25 which was an improvement on my original proposal, and the technique used by the interface code generating tool 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"));
}About the Code The above code defines an interface reference named
baz
manually, which can refer to any type which provides functions matching the function pointers in thebaz::table
.Every interface reference variable stores a pointer to its function table through the variable
baz::_m_t
and stores a pointer to the object inbaz::_m_a
.What the code does is generate a static function table for every class
T
that is passed to abaz
. These static function tables have typebaz::table_type
and are namedbaz::function<T>::table
. Even though there is only one name, because it is a static template variable ofbaz::function
, there is a separate one created for every instance ofbaz::function
. To put it another way, we use the compiler to generate a function table for every class - interface pair possibility at compile-time.Summary The technique described, even though it is sophisticated, is still a simplification of how the BIL is implemented. The BIL is considerably more complex because it also provides support for a wide range of techniques such as Aspect Oriented Programming, Delegations, Generic Programming, and more. The BIL is also required to work around certain limitations of the C++ pre-processor. I will write more in the future about the BIL as it matures, and is released officially into the public domain. Hopefully, this article does help explain the theory behind the technique and can provide you with some insight into the interface reference types.
多年来,框架的体系结构为我们提供了很好的服务,但由于我们终于有了所有安全文件,可以使用比 Red Hat 默认包含的编译器更现代的编译器,我想开始升级框架以使用现代 C++。
有没有人有更好的方法来设计支持动态多态性的接口(interface)/实现架构?
最佳答案
不确定是不是你想要的:
// 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::foo
/baz::bar
可能会被 operator->
省略,但会更改调用者的语法。虽然所有这些并不真正需要 C++11 或更高版本(智能指针除外)
关于c++ - Dave Abrahams 和 Chris Diggins 的 C++ 接口(interface)思想有哪些现代替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58400925/
(我假设知道这个问题中的 Abrahams/Dimov example。) 假设标题中有一些 3rd 方代码,您无法修改: template void f(T); // (1) base tem
abraham 的 twitteroauth 库是否适用于 update_with_media? 我正在使用下面的代码,但它返回了我的 stdClass 对象( [请求] =>/1/statuses/
我正在尝试使用 Abraham 的 twitteroauth 库 (TwitterOAuth v0.2.0-beta2) 实现来自 ajax 的 upload_with_media 请求。我对基本帖子
我正在使用这个库... http://github.com/abraham/twitteroauth 我可以更新状态和内容,但似乎找不到直接消息的功能。 此外,还有其他任何我可以使用的库吗? 最佳答案
首先,我必须说我已经阅读了很多关于这个问题的帖子,但我仍然无法解决它。 我正在使用 Abraham 的 TwitterOAuth 库发送大量转发,代码如下: $connection = new Twi
我正在开发一个简单的函数来获取我的推特关注者的 ID。我可以使用 oauth 登录并获得结果,但我无法获得 header 信息,因此我无法使用 header 中的 x_rate_limit_remai
我最近在我的公司继承了一个遗留的模拟框架,它是在 2000 年代初期编写的,当时主要作者正在从 C 和 Fortran 过渡到 C++。接口(interface)/实现架构遵循 Dave Abraha
以下代码几乎是从 David Abrahams 和 Aleksey Gurtovoy 所著的《C++ 模板元编程:Boost and Beyond 中的概念、工具和技术》一书的第 9.1.1 节中逐字
我是一名优秀的程序员,十分优秀!