面试题答案
一键面试类继承体系设计
假设我们有一个简单的图形类继承体系,包含基类 Shape
和派生类 Circle
与 Rectangle
。
#include <iostream>
#include <memory>
class Shape {
public:
virtual void draw() const = 0;
virtual ~Shape() = default;
};
class Circle : public Shape {
double radius;
public:
Circle(double r) : radius(r) {}
void draw() const override {
std::cout << "Drawing a Circle with radius " << radius << std::endl;
}
};
class Rectangle : public Shape {
double width, height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
void draw() const override {
std::cout << "Drawing a Rectangle with width " << width << " and height " << height << std::endl;
}
};
对象创建
std::unique_ptr
:- 适用于对象唯一拥有所有权的场景。
- 创建
Circle
对象示例:
std::unique_ptr<Shape> createCircle() {
return std::make_unique<Circle>(5.0);
}
std::shared_ptr
:- 适用于多个对象可能共享所有权的场景。
- 创建
Rectangle
对象示例:
std::shared_ptr<Shape> createRectangle() {
return std::make_shared<Rectangle>(3.0, 4.0);
}
对象销毁
std::unique_ptr
:- 当
std::unique_ptr
离开作用域时,它所管理的对象会自动销毁。 - 例如:
- 当
{
std::unique_ptr<Shape> shape = createCircle();
// 在这里使用 shape
} // shape 离开作用域,Circle 对象被销毁
std::shared_ptr
:- 当最后一个指向对象的
std::shared_ptr
被销毁时,对象才会被销毁。 - 例如:
- 当最后一个指向对象的
{
std::shared_ptr<Shape> shape1 = createRectangle();
std::shared_ptr<Shape> shape2 = shape1; // 共享所有权
} // shape1 和 shape2 离开作用域,引用计数降为 0,Rectangle 对象被销毁
对象转换
- 使用
dynamic_cast
与智能指针:- 对于
std::unique_ptr
:
- 对于
std::unique_ptr<Shape> shape = createCircle();
std::unique_ptr<Circle> circlePtr = std::unique_ptr<Circle>(dynamic_cast<Circle*>(shape.release()));
if (circlePtr) {
circlePtr->draw();
}
- 对于
std::shared_ptr
:
std::shared_ptr<Shape> shape = createRectangle();
std::shared_ptr<Rectangle> rectanglePtr = std::dynamic_pointer_cast<Rectangle>(shape);
if (rectanglePtr) {
rectanglePtr->draw();
}
注意事项
- 虚析构函数:
- 基类(如
Shape
)必须有虚析构函数,这样在通过基类指针(智能指针也一样)销毁派生类对象时,才能正确调用派生类的析构函数。
- 基类(如
std::weak_ptr
的使用:- 当存在循环引用可能导致内存泄漏时,可使用
std::weak_ptr
。例如,假设Shape
类有一个指向另一个Shape
的成员指针,为避免循环引用:
- 当存在循环引用可能导致内存泄漏时,可使用
class Shape {
public:
virtual void draw() const = 0;
virtual ~Shape() = default;
std::weak_ptr<Shape> relatedShape;
};
- 可通过
std::weak_ptr
获取std::shared_ptr
来访问对象,但需先检查std::weak_ptr
是否有效:
std::shared_ptr<Shape> otherShape = relatedShape.lock();
if (otherShape) {
otherShape->draw();
}
dynamic_cast
失败处理:dynamic_cast
对于无效转换会返回空指针(对于指针类型)或抛出异常(对于引用类型)。在使用dynamic_cast
与智能指针时,要检查转换结果,避免空指针解引用。