传统的virtual动态多态,经常会有下面这样的使用需求:
cpp
#include <iostream>
#include <vector>
// 声明一个包含virtual虚函数的基类
struct shape
{
virtual ~shape() {}
virtual void draw() = 0;
};
// 派生,实现virtual虚函数
struct rectangle : shape
{
virtual void draw() override
{
std::cout << "rectangle" << std::endl;
}
};
// 派生,实现virtual虚函数
struct circle : shape
{
virtual void draw() override
{
std::cout << "circle" << std::endl;
}
};
int main()
{
// 由于要用vector容器来保存各种不同的对象,所以这里容器元素的类型只能使用基类指针
std::vector<shape*> vec;
vec.emplace_back(new rectangle());
vec.emplace_back(new circle());
// 通过virtual动态多态调用,来实现调用真正的对象类型的成员函数
for (const auto& p : vec)
{
p->draw();
}
// 输出:
// rectangle
// circle
}
上面同样的需求,换成proxy库来实现是这样的:
cpp
#include <iostream>
#include <vector>
#include "proxy.h"
// 声明一个代理类,最终会通过这个代理类去调用真正的类对象的成员函数
struct draw : pro::dispatch<void()>
{
template <class T>
void operator()(T& self) { self.draw(); }
};
struct shape : pro::facade<draw> {};
// 不需要派生,不需要virtual虚函数
struct rectangle
{
void draw()
{
std::cout << "rectangle"<< std::endl;
}
};
// 不需要派生,不需要virtual虚函数
struct circle
{
void draw()
{
std::cout << "circle" << std::endl;
}
};
int main()
{
// 这里容器元素的类型是个proxy的代理类型
std::vector<pro::proxy<shape>> shapes;
shapes.emplace_back(pro::make_proxy<shape>(rectangle()));
shapes.emplace_back(pro::make_proxy<shape>(circle()));
// 注意这里的调用方式和virtual动态多态的调用方式不同
for (auto& p : shapes)
{
p.invoke<draw>();
}
// 输出:
// rectangle
// circle
}
可以看到,换成proxy库之后,不再有virtual虚函数,而且是非侵入式的,我觉得这种方式非常棒,很优雅。至于性能测试,我没有去做。
详情见这个开源仓库地址:https://github.com/microsoft/proxy