虚函数与动态绑定

C++ 通过类的继承与虚函数的动态绑定,实现了多态。这种特性,使得我们能够用基类的指针,访问子类的实例。例如我们可以实现一个名为 Animal 的基类,以及 Cat, Dog 等子类,并通过在子类中重载虚函数 jump,实现不同动物的跳跃动作。而后我们可以通过访问 Zoo 类的实例中存有 Animal 指针的数组,让动物园中所有的动物都跳一遍。

1
2
3
4
5
6
7
8
9
10
11
12
class Zoo {
...
private:
std::vector<shared_ptr<Animal>> animals;
public:
void () {
for (auto animal : animals) {
animal->jump();
}
}
...
}

在每次执行 animal->jump() 的时候,系统会检查 animal 指向的实例实际的类型,然后调用对应类型的 jump 函数。这一步骤需要通过查询虚函数表(vtable)来实现;由于实际 animal 指向对象的类型在运行时才确定(而不是在编译时就确定),所以这种方式称为动态绑定(或者运行时绑定)。

因为每次都需要查询虚函数表,所以动态绑定会降低程序的执行效率。为了兼顾多态与效率,有人提出了 Curiously Recurring Template Pattern 的概念。

阅读全文 »

这是一篇简单的记录,因为我总是忘记如何从硬编码的 Array 中初始化得到一个 Vector。

1
2
3
4
5
6
7
8
9
#include <vector>

using std::vector;

int main () {
const int arr[] = {16,2,77,29};
vector<int> vec (arr, arr + sizeof(arr) / sizeof(arr[0]));
return 0;
}

这篇文章的缘起有二:

  • 很多人主张「应当在几乎所有情况下使用 C 风格的 I/O」(比如这里),而我很怀疑;
  • 另一方面,在刷 POJ 的时候,使用 std::cin 确实能 TLE 而改成 std::scanf 就 AC 了,因此想试试看 std::cin 能否加速。

中文网络里,已有码农场byvoid 菊苣的讨论。不过二者对于原理的解释,自我感觉都不够清晰;又本着自己动手做实验的坚持,决定写下这篇文章,探讨 C++ 的读入速度的问题,特别是读入文件速度的问题。

阅读全文 »

大多数命令行工具,都会提供一些选项。在不同的选项组合之下,这些工具会有不同的行为。GNU 标准的命令行选项解析工具是 getopts,它比其兄弟 getopt 更为强大。除了介绍 getopts 的用法之外,这里还会介绍两种手工解析参数的方法。

在正式介绍之前,有必要区分几个概念(在 Shell 脚本中)。

  • Argument, Option: 中文对应「选项」,形如 -a, --save 的都是选项;选项可以接收参数(Parameter),也可以不接受参数。
  • Flag: 中文对应「标签」,形如 -v(verbose);标签是布尔值,不接受参数。

下面正式开始介绍。

阅读全文 »