C++类构造函数中能否使用可访问该类成员的lambda表达式
问题解答
完全可以实现无额外参数的透明调用,你现在卡壳的核心原因是作用域问题:你在superclass构造函数内定义lambda时,当前作用域的this指向的是superclass实例,此时你要创建的subclass对象还未完成构造,在这个位置根本不可能直接捕获到subclass实例的指针。
不需要修改get_color的对外调用接口,也不需要在调用颜色生成函数时传额外参数,只需要在子类内部做一层极薄的绑定包装即可:
- 调整子类构造函数的入参类型,改为接收一个工厂函数:该工厂函数入参为子类自身的指针,返回值为你需要的
rgb(int)类型的颜色生成函数 - 在子类构造函数内部,将自身的
this指针传入工厂函数,拿到绑定了当前实例的生成函数后存为成员 - 外部传入lambda时,只需要在参数列表里声明一个子类指针类型的形参,在lambda内部用这个指针访问子类成员,效果和直接捕获子类
this完全一致,这层绑定逻辑是子类内部完成的,对外完全不可见。
可直接运行的实现代码
#include <functional> // 基础RGB结构体 struct rgb {unsigned char r, g, b}; // 前置声明HSV转RGB函数,按你自己的实现补全即可 rgb hsv_to_rgb(float h, float s, float v); // 你已有的、预存RGB颜色列表的基类,补全基础接口 class BaseColorList { public: virtual ~BaseColorList() = default; virtual rgb get_color(int index) = 0; }; // 动态生成颜色的子类,继承自上述基类 class DynamicColorList : public BaseColorList { std::function<rgb(int)> create_color; public: // 构造函数接收工厂函数,而非直接接收最终生成函数 DynamicColorList(std::function<rgb(DynamicColorList*, int)> color_factory) { // 内部绑定当前实例this,包装为仅需要索引参数的生成函数 create_color = [this, color_factory](int idx) { return color_factory(this, idx); }; } rgb get_color(int index) override { // 调用时无额外参数,和你预期的接口完全一致 return create_color(index); } // 子类任意成员都可以在传入的lambda中通过self指针访问 float saturation() { return 1.0; } float value() { return 1.0; } }; // 你代码中命名为superclass的业务使用类 class ColorService { BaseColorList* colorlist; public: ColorService() { // 传入lambda时,第一个参数就是子类实例的指针,用起来和捕获this无区别 colorlist = new DynamicColorList([](DynamicColorList* self, int x) -> rgb { return hsv_to_rgb(x % 360, self->saturation(), self->value()); }); } ~ColorService() { delete colorlist; } };
注意事项
- 该实现没有额外运行时开销,编译器开启优化后,这层包装会被完全内联,和直接捕获指针的性能没有区别
- 不要在子类构造函数内部调用
create_color,此时子类对象尚未完成初始化,通过this访问成员会触发未定义行为,等构造完成后调用就完全安全 - 如果你不想调整构造函数的入参类型,也可以给子类加一个后置的
init方法,等子类对象构造完成后再传入绑定了this的生成函数,但这种写法需要手动调用初始化方法,安全性不如上述工厂方案。
内容的提问来源于stack exchange,提问作者VolcanoPig
相关产品推荐
相关产品推荐

