You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在类内部将this以shared_ptr形式传入DoublePerimeter函数?

问题解决与设计分析

一、先修正代码里的基础bug

你贴的Square类代码有几个语法问题,先改了才能正常运行:

  1. 构造函数不能加void返回值,应该写成Square(float aside) : side(aside) {}
  2. C++里类继承默认是private,这样Shape的接口在Square里不可见,必须改成public继承:class Square : public Shape
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 16:25:14