虚函数是C++实现多态的工具,在运行时根据虚表决定调用合适的函数。这被称作动态分发。虚函数很好的实现了多态的要求,但是在运行时引入了一些开销,包括:

  1. 对每一个虚函数的调用都需要额外的指针寻址
  2. 虚函数通常不能被inline,当虚函数都是小函数时会有比较大的性能损失
  3. 每个对象都需要有一个额外的指针指向虚表

所以如果是一个对性能要求非常严格的场合,我们就需要用别的方式来实现分发,这就是今天这篇博客的主角CRTP

CRTP通过模板实现了静态分发,会带来很多性能的好处。可以参见The cost of dynamic (virtual calls) vs. static (CRTP) dispatch in C++看一下性能比较。

 

下面简单介绍一下怎么实现CRTP。

 

首先看我们的父类:

 1
2
3
4
5
6
7
8
9
10
11
12
13
template<typename Derived>  class Parent
{
public:
void SayHi()
{
static_cast<Derived*>(this)->SayHiImpl();
}
private:
void SayHiImpl() // no need if no need the default implementation
{
cout << "hi, i'm default!" << endl;
}
};

它是一个模板类,它有一个需要接口函数是SayHi。它有一个默认实现在SayHiImpl中。

 

再来看看它的子类:

 1
2
3
4
5
6
7
8
9
10
11
12
class ChildA :public Parent<ChildA>
{
public:
void SayHiImpl()
{
cout << "hi, i'm child A!" << endl;
}
}; class ChildB :public Parent<ChildB>
{
};

我们可以看到ChildAChildB继承自这个模板类,同时ChildA有自己的实现。

 

在写一个普通的用虚函数实现分发的类:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class ParentB
{
public:
void virtual SayHi()
{
cout << "hi, i'm default!" << endl;
}
}; class ChildC : public ParentB
{
public:
void SayHi()
{
cout << "hi, i'm ChildC!" << endl;
}
}; class ChildD : public ParentB
{
};

 

然后是调用这两个父类的函数:

1
2
3
4
5
6
7
8
9
template<typename Derived> void CRTP(Parent<Derived>& p)
{
p.SayHi();
} void Dynamic(ParentB& p)
{
p.SayHi();
}

 

再来看看main函数:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int _tmain(int argc, TCHAR* argv[])
{ ChildA a;
CRTP(a);
cout << "size of ChildA: " << sizeof(a) << endl; ChildB b;
CRTP(b);
cout << "size of ChildB: " << sizeof(b) << endl; ChildC c;
Dynamic(c);
cout << "size of ChildC: " << sizeof(c) << endl; ChildD d;
Dynamic(d);
cout << "size of ChildD: " << sizeof(d) << endl; return 0;
}

 

如果运行这个程序,可以看到如下的输出,可以看到CRTP可以实现和虚函数一样的功能,但是内存大小会有很大优势,关于对象内存可以参见我之前的博客怎么看C++对象的内存结构 和 怎么解密C++的name Mangling

 

1
2
3
4
5
6
7
8
9
hi, i'm child A!
size of ChildA: 1
hi, i'm default!
size of ChildB: 1
hi, i'm ChildC!
size of ChildC: 4
hi, i'm default!
size of ChildD: 4
Press any key to continue . . .

 

完整代码参见gist

C++的静态分发(CRTP)和动态分发(虚函数多态)的比较的更多相关文章

  1. java的静态代理、jdk动态代理和cglib动态代理

    Java的代理就是客户端不再直接和委托类打交道,而是通过一个中间层来访问,这个中间层就是代理.使用代理有两个好处,一是可以隐藏委托类的实现:二是可以实现客户与委托类之间的解耦,在不修改委托类代码的情况 ...

  2. 《CMake实践》笔记三:构建静态库(.a) 与 动态库(.so) 及 如何使用外部共享库和头文件

    <CMake实践>笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE <CMake实践>笔记二:INSTALL/CMAKE_INSTALL_PREFIX &l ...

  3. 浅谈在静态页面上使用动态参数,会造成spider多次和重复抓取的解决方案

    原因: 早期由于搜索引擎蜘蛛的不完善,蜘蛛在爬行动态的url的时候很容易由于网站程序的不合理等原因造成蜘蛛迷路死循环. 所以蜘蛛为了避免之前现象就不读取动态的url,特别是带?的url 解决方案: 1 ...

  4. 在Linux中创建静态库.a和动态库.so

    转自:http://www.cnblogs.com/laojie4321/archive/2012/03/28/2421056.html 在Linux中创建静态库.a和动态库.so 我们通常把一些公用 ...

  5. 动态库DLL加载方式-静态加载和动态加载

    静态加载: 如果你有a.dll和a.lib,两个文件都有的话可以用静态加载的方式: message函数的声明你应该知道吧,把它的声明和下面的语句写到一个头文件中 #pragma comment(lib ...

  6. WPF中静态引用资源与动态引用资源的区别

    WPF中静态引用资源与动态引用资源的区别   WPF中引用资源分为静态引用与动态引用,两者的区别在哪里呢?我们通过一个小的例子来理解. 点击“Update”按钮,第2个按钮的文字会变成“更上一层楼”, ...

  7. 解决在静态页面上使用动态参数,造成spider多次和重复抓取的问题

    我们在使用百度统计中的SEO建议检查网站时,总是发现“静态页参数”一项被扣了18分,扣分原因是“在静态页面上使用动态参数,会造成spider多次和重复抓取”.一般来说静态页面上使用少量的动态参数的话并 ...

  8. C++的静态联编和动态联编

    联编的概念 联编是指一个计算机程序自身彼此关联的过程,在这个联编过程中,需要确定程序中的操作调用(函数调用)与执行该操作(函数)的代码段之间的映射关系. 意思就是这个函数的实现有多种,联编就是把调用和 ...

  9. Linux 静态链接库和动态连接库

    (0)文件夹 VMware 下安装Ubuntu的吐血经历 零基础学习Shell编程 Linux下的makefile的妙用 Linux调试神器 -- gdb 十分钟学会Python的基本类型 Linux ...

随机推荐

  1. 如何定时备份远程mysql数据库

    通常,站长们都没有自己的服务器,每天都要手动备份数据库那也很麻烦.这里推荐一个方法,利用windows的计划任务来实现. 前提:本地机器上装有mysql服务. 假设本地机器上mysql服务目录  d: ...

  2. hadoop1中partition和combiner作用

    ---恢复内容开始--- 1.解析Partiton 把map任务的输出的中间结果按照key的范围进行划分成r份,r代表reduce任务的个数.hadoop默认有个类HashPartition实现分区, ...

  3. C# 实现繁体字和简体字之间的转换

    今天收到一个需求,将一组简体的汉字转换成繁体的汉字,刚开始有点茫然,后来在网上搜了一下思路,结果很少有涉及,终于我在看了MSDN后找到了如何解决,可能这方面对一些高程来说很Easy,但是除了高程还有很 ...

  4. web design tools

    https://www.google.com/webdesigner/ http://html.adobe.com/edge/inspect/ http://www.creativebloq.com/ ...

  5. CSS3------background-size(背景图片尺寸属性)

    background-size 可以设置背景图片的大小,数值包括 长度length和百分比percentage. 并且会根据背景原点位置 background-origin 设置其图片覆盖的范围.那么 ...

  6. 对指定文件生成数字摘要的MD5工具类

    md5特点:压缩性.不可逆性,经常用于传值过程中的值加密或文件加密static char hexdigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', ...

  7. python基础知识(引用)

    文章连接:http://xianglong.me/article/how-to-code-like-a-pythonista-idiomatic-python/

  8. 【原创】Matlab中plot函数全功能解析

    [原创]Matlab中plot函数全功能解析 该帖由Matlab技术论(http://www.matlabsky.com)坛原创,更多精彩内容参见http://www.matlabsky.com 功能 ...

  9. 【转】Spring 注解学习手札(超好的springmvc注解教程)

    Spring 注解学习手札(一) 构建简单Web应用 Spring 注解学习手札(二) 控制层梳理 Spring 注解学习手札(三) 表单页面处理 Spring 注解学习手札(四) 持久层浅析 Spr ...

  10. jquery之ajaxfileupload异步上传插件

    点我下载工程代码由于项目需求,在处理文件上传时需要使用到文件的异步上传.这里使用Jquery Ajax File Uploader这个组件下载地址:http://www.phpletter.com/d ...