惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Stack Overflow Blog
Stack Overflow Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
爱范儿
爱范儿
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
有赞技术团队
有赞技术团队
罗磊的独立博客
博客园 - 三生石上(FineUI控件)
小众软件
小众软件
L
LINUX DO - 最新话题
T
Troy Hunt's Blog
博客园_首页
量子位
Jina AI
Jina AI
S
SegmentFault 最新的问题
IT之家
IT之家
Hacker News - Newest:
Hacker News - Newest: "LLM"
大猫的无限游戏
大猫的无限游戏
N
News | PayPal Newsroom
P
Proofpoint News Feed
Cyberwarzone
Cyberwarzone
S
Securelist
Google Online Security Blog
Google Online Security Blog
P
Privacy International News Feed
博客园 - Franky
美团技术团队
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
NISL@THU
NISL@THU
C
Cisco Blogs
V
Vulnerabilities – Threatpost
腾讯CDC
The Hacker News
The Hacker News
K
Kaspersky official blog
C
Cyber Attacks, Cyber Crime and Cyber Security
雷峰网
雷峰网
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Security Archives - TechRepublic
Security Archives - TechRepublic
A
About on SuperTechFans
Webroot Blog
Webroot Blog
The Register - Security
The Register - Security
Scott Helme
Scott Helme
B
Blog
Security Latest
Security Latest
Last Week in AI
Last Week in AI
Google DeepMind News
Google DeepMind News
W
WeLiveSecurity
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tenable Blog
Blog — PlanetScale
Blog — PlanetScale
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
Schneier on Security

核桃的炼金工坊

2023 韩国游记 C++23: Flat Containers Deducing This Stateful Metaprogramming 推し、燃ゆ Customization Point Object 2020 总结 搞了个 C++ 构建系统 软件设计哲学(NOTE) Paxos Note 关于 cpp 可见性的黑魔法后门 一个关于 private member function detect 的 SFINAE 模板 User-defined conversion and Copy elision VIM and Latex Compare Between CRTP and Virtual Compile Time Reflection in C++11 C++11内存模型 在C++17中的部分新特性 Const Reference of Pointer
Interface in C++
Hawtian Wang · 2018-08-06 · via 核桃的炼金工坊

我记得我不止一次提到说,我更喜欢 golang 的泛型设计。一个优秀的泛型系统,我希望是来表示一个方法可以接受什么。应该是一个类似于 concept 的概念。我们都知道,在 C++ 里面,我们更多的使用虚函数来实现这个功能,就像下面这样:

struct IPerson {
  virtual std::string Name() = 0;
  virtual uint32_t Age() = 0;
};

我们搞了一个几个纯虚函数来表示一个接口类,然后我们都会搞一些类来继承这个类,就像下面这样:

struct Student : public IPerson {
  std::string Name() override;
  uint32_t Age() override;
};

那在使用的地方:

这已经是我们一般在写代码时候的常规做法了,但是在这样的情况下,我们要求了所有使用这个的地方,都只能使用指针或者引用。因为我们不能对一个对象来搞这些东西。

再回想一下,golang 的泛型的样子,我们有没有一个办法,可以搞一个类似于 interface 的东西来让一个对象也可以表示这些东西呢?

基于上面的问题,考虑这个问题的背后是表示的是个什么类型的多态问题。Ok,显然是个运行时多态。编译时多态的问题可以配合 template, constexpr 来解决。那么运行时多态在原本的 C++ 是通过虚函数来解决的。虚函数的实现,又是通过一个虚函数表来实现的。那么问题来了,我们可不可以自己来维护一个虚函数表来达到我们想要的效果呢? 上面我们需要的接口类,显然我们可以提炼出来一个这样的虚函数表:

struct vtable {
  std::string (*Name)(void*);
  uint32_t (*Age)(void*);
};

这个虚函数表表示了这个接口需要哪些接口,在这里使用 void* 来表示任意类型的指针。 那有了这个虚函数表之后,我们应该怎么使用这个呢?就像这个这样:

template<typename T>
vtable vtable_for = {
  [](void* p) {
    return static_cast<T*>(p)->Name();
  },
  [](void*) {
    return static_cast<T*>(p)->Age();
  },
};

这里用了 C++14 的新特性:变量模板,来构造了一个静态的全局变量,来表示对应的制定类型的虚函数表实现。 在有了上面两个东西的基础上,就得到了接口类的实现:

struct Person {
  template<typename T>
  Person(T t) : vtable_( &vtable_for<T> ), p(new T{t}) {}
 private:
  vtable* vtable_;
  void* p;
};

接下来,这个类就可以很棒了。你可以像下面这么定义:

std::vector<Person> persons;

persons.push_back(Student{});
persons.push_back(Teacher{});
...

用起来的时候,一切都看起来和 golang 的那个版本差不多了呢。


Reference:

  1. https://zh.wikipedia.org/wiki/C%2B%2B14#%E5%8F%98%E9%87%8F%E6%A8%A1%E6%9D%BF