如何在类内部将this以shared_ptr形式传入DoublePerimeter函数?
问题解决与设计分析
一、先修正代码里的基础bug
你贴的Square类代码有几个语法问题,先改了才能正常运行:
- 构造函数不能加
void返回值,应该写成Square(float aside) : side(aside) {} - C++里类继承默认是private,这样Shape的接口在Square里不可见,必须改成public继承:
class Square : public Shape - Shape类的
GetPerimeter必须声明为虚函数,否则用shared_ptr<Shape>指向Square时,调用的会是Shape的版本(如果有的话),而非Square的实现。正确的Shape基类应该是:
#include <memory> class Shape { public: virtual float GetPerimeter() = 0; // 纯虚函数,强制子类实现 virtual ~Shape() = default; // 虚析构,避免shared_ptr释放时内存泄漏 };
二、正确传递shared_ptr给DoublePerimeter的两种方式
方式1:正确用enable_shared_from_this
你之前用enable_shared_from_this但lock为空,大概率是两个原因:要么当前对象没被任何shared_ptr持有,要么继承方式不对。正确的做法是让基类Shape继承enable_shared_from_this,代码如下:
class Shape : public std::enable_shared_from_this<Shape> { public: virtual float GetPerimeter() = 0; virtual ~Shape() = default; }; class Square : public Shape { float side = 1; public: Square(float aside) : side(aside) {} float GetPerimeter() override { return 4 * side; } // 用override明确重写虚函数 void Computation() { // 调用shared_from_this()拿到当前对象的shared_ptr DoublePerimeter(shared_from_this()); } }; float DoublePerimeter(std::shared_ptr<Shape> shape) { return 2 * shape->GetPerimeter(); }
关键注意点:shared_from_this()只能在对象已经被shared_ptr管理的时候调用,比如必须用make_shared创建Square对象:
int main() { auto square = std::make_shared<Square>(3); square->Computation(); // 这里调用完全安全 // 绝对不能这样:Square s(2); s.Computation(); 会触发未定义行为 return 0; }
方式2:兼容栈对象的重载(不推荐但可用)
如果你的Square对象可能在栈上创建,没法用shared_from_this(),可以给DoublePerimeter加个裸指针的重载:
// 先写裸指针版本的实现 float DoublePerimeter(Shape* shape) { return 2 * shape->GetPerimeter(); } // 原shared_ptr版本调用裸指针版本 float DoublePerimeter(std::shared_ptr<Shape> shape) { return DoublePerimeter(shape.get()); } // 然后Square的Computation直接传this void Computation() { DoublePerimeter(this); }
这种方式要注意:如果DoublePerimeter内部会保存指针,裸指针版本会有悬空风险,只适合临时计算的场景。
三、设计合理性讨论
当前设计的问题
强制DoublePerimeter接收shared_ptr<Shape>是个没必要的限制:
- 栈上创建的Shape子类对象没法直接调用这个函数
- 增加了调用成本,必须处理shared_ptr的传递逻辑
是否必须改成成员函数?
不是必须,但改成成员函数更符合面向对象逻辑——周长翻倍属于形状自身的行为,代码也更简洁:
class Shape { public: virtual float GetPerimeter() = 0; virtual ~Shape() = default; // 直接加成员函数 float DoublePerimeter() { return 2 * GetPerimeter(); } }; // Square的Computation里直接调用 void Computation() { auto result = DoublePerimeter(); }
这种方式不管对象在栈还是堆上都能用,完全不用管指针的问题。
如果坚持用非成员函数
推荐改成接收const Shape&引用,比传shared_ptr灵活得多:
float DoublePerimeter(const Shape& shape) { return 2 * shape.GetPerimeter(); } // Square的Computation里传*this就行 void Computation() { DoublePerimeter(*this); }
不管是栈对象、堆对象还是shared_ptr管理的对象,都能通过解引用传递,通用性拉满。
总结
- 要保留shared_ptr版本的话,必须确保对象被shared_ptr持有,然后正确用
enable_shared_from_this - 从设计和实用性来看,改成成员函数或者让非成员函数接收引用,比强制传shared_ptr合理得多
内容的提问来源于stack exchange,提问作者the.polo
相关产品推荐
相关产品推荐

