关于虚函数及其替代方式效率对比
这个可以参考effective c++
http://www.cppblog.com/tiandejian/archive/2011/12/25/epp_35.html
这里给出一个测试程序 对比了3种不同实现方案的效率,这三种方案的效果是等价的
1.使用虚函数
2.使用std::function
3.使用模板的trick
template<typename Derived> class Base; class A : public Base<A>; 使用Derived::..
这里特别注意这个tric能够在保证效率的同时能保持继承多态
这个设计非常有用 把核心的多次调用代码设计为非虚函数,而外层是虚函数保持动态多态特性,在性能和灵活性最好的折中。
不过问题是似乎没办法处理非static
当然模板方法效率最高,比较奇怪的是std::function效率最低,而虚函数其实代价很小,10000000也就是1000万的调用也只有多出不到0.02s
结论:
1.除非极端需要效率虚函数是最好最优雅简单的实现方式
2.极端需要效率考虑使用模板tric
3.std::function最灵活 一般不需要考虑使用,考虑写法会麻烦一些 同时效率较低 当然也效率一般也降低的不是太多
一般来说除非极端情况都不会是效率瓶颈
./test_derive
I0521 16:10:00.118948 23283 test_derive.cc:98] A deal
I0521 16:10:00.119071 23283 test_derive.cc:58] base func
I0521 16:10:00.119079 23283 test_derive.cc:103] A func
I0521 16:10:00.119086 23283 test_derive.cc:103] A func
I0521 16:10:00.119091 23283 test_derive.cc:117] B deal
I0521 16:10:00.119096 23283 test_derive.cc:58] base func
I0521 16:10:00.119101 23283 test_derive.cc:122] B func
I0521 16:10:00.119106 23283 test_derive.cc:122] B func
I0521 16:10:00.699487 23283 time_util.h:141] std::function using: [580.364 ms] (0.580362 s)
I0521 16:10:00.852361 23283 time_util.h:141] virutal using: [152.82 ms] (0.152819 s)
I0521 16:10:00.992095 23283 time_util.h:141] template using: [139.72 ms] (0.139718 s)
/**
* ==============================================================================
*
* \file test_derive.cc
*
* \author chenghuige
*
* \date 2015-05-21 15:01:54.463482
*
* \Description:
*
* ==============================================================================
*/
#define private public
#define protected public
#include "common_util.h"
using namespace std;
using namespace gezi;
DEFINE_int32(vl, 0, "vlog level");
DEFINE_int32(level, 0, "min log level");
DEFINE_string(type, "simple", "");
DEFINE_bool(perf, false, "");
DEFINE_int32(num, 1, "");
DEFINE_string(i, "", "input file");
DEFINE_string(o, "", "output file");
class IBase
{
public:
virtual void eval() = 0;
virtual void speed_virtual() = 0;
virtual void speed_template() = 0;
virtual void speed_function() = 0;
};
template<typename Derived>
class Base : public IBase
{
public:
virtual void eval() override
{
deal();
func();
Derived::func();
_func();
}
virtual void deal()
{
VLOG(0) << "base deal";
}
static void func()
{
VLOG(0) << "base func";
}
virtual void speed_virtual() override
{
for (size_t i = 0; i < 10000000; i++)
{
deal();
}
}
virtual void speed_template() override
{
for (size_t i = 0; i < 10000000; i++)
{
Derived::func();
}
}
virtual void speed_function()
{
for (size_t i = 0; i < 10000000; i++)
{
_func();
}
}
std::function<void()> _func;
};
class A : public Base < A >
{
public:
A()
{
_func = A::func;
}
virtual void deal()
{
VLOG(0) << "A deal";
}
static void func()
{
VLOG(0) << "A func";
}
};
class B : public Base < B >
{
public:
B()
{
_func = B::func;
}
virtual void deal()
{
VLOG(0) << "B deal";
}
static void func()
{
VLOG(0) << "B func";
}
};
void run()
{
shared_ptr<IBase> a = make_shared<A>();
shared_ptr<IBase> b = make_shared<B>();
a->eval();
b->eval();
}
void run_perf()
{
FLAGS_v = -1;
shared_ptr<IBase> a = make_shared<A>();
shared_ptr<IBase> b = make_shared<B>();
{
Notifer nt("std::function", -1);
a->speed_function();
b->speed_function();
}
{
Notifer nt("virutal", -1);
a->speed_virtual();
b->speed_virtual();
}
{
Notifer nt("template", -1);
a->speed_template();
b->speed_template();
}
}
int main(int argc, char *argv[])
{
google::InitGoogleLogging(argv[0]);
google::InstallFailureSignalHandler();
google::SetVersionString(get_version());
int s = google::ParseCommandLineFlags(&argc, &argv, false);
if (FLAGS_log_dir.empty())
FLAGS_logtostderr = true;
FLAGS_minloglevel = FLAGS_level;
//LogHelper::set_level(FLAGS_level);
if (FLAGS_v == 0)
FLAGS_v = FLAGS_vl;
run();
run_perf();
return 0;
}