Skip to content

C++ 类与对象

类把数据、不变量和操作组合成一个类型。良好的类应让有效状态容易构造,让资源随对象生命周期自动获得和释放。

封装与构造

cpp
class Point {
public:
    Point(double x, double y) : x_(x), y_(y) {}

    [[nodiscard]] double x() const noexcept { return x_; }
    [[nodiscard]] double y() const noexcept { return y_; }

    void translate(double dx, double dy) noexcept {
        x_ += dx;
        y_ += dy;
    }

private:
    double x_{};
    double y_{};
};

成员按声明顺序初始化,而不是按初始化列表的书写顺序。需要维持不变量时,应在构造完成前验证参数。

特殊成员函数

编译器可能生成默认构造、析构、复制构造、复制赋值、移动构造和移动赋值。是否自动生成以及是否被删除,取决于成员与用户声明的特殊成员。

Rule of Zero

cpp
class Document {
    std::string title_;
    std::vector<std::string> lines_;
};

成员都能自行管理资源时,不写任何特殊成员函数通常最好。这称为 Rule of Zero。

独占资源

cpp
class Buffer {
public:
    explicit Buffer(std::size_t size)
        : data_(std::make_unique<std::byte[]>(size)), size_(size) {}

    Buffer(const Buffer&) = delete;
    Buffer& operator=(const Buffer&) = delete;
    Buffer(Buffer&&) noexcept = default;
    Buffer& operator=(Buffer&&) noexcept = default;

private:
    std::unique_ptr<std::byte[]> data_;
    std::size_t size_{};
};

显式删除复制并默认移动,能准确表达独占所有权。若确实需要复制,应定义深复制,而不是让两个对象管理同一裸指针。

const 与引用限定

cpp
class Text {
public:
    const std::string& value() const & { return value_; }
    std::string value() && { return std::move(value_); }
private:
    std::string value_;
};

const 成员函数不能修改普通成员;引用限定符还能区分对象是左值还是右值,避免从临时对象返回悬空引用。

多态

cpp
class Operator {
public:
    virtual ~Operator() = default;
    virtual void execute() = 0;
};

需要通过基类指针删除派生对象时,基类析构函数必须是虚函数。组合通常比继承更灵活;只有明确存在“is-a”关系和运行时替换需求时才采用动态多态。

TIP

先让成员类型承担资源管理,再设计类的不变量。能使用默认特殊成员函数时,就不要手写复制、移动和析构逻辑。

SIGNAL MAINTAINED · BUILT FROM MARKDOWN