1. C++类与对象深度解析
在C++编程中,类和对象是最基础也是最核心的概念。很多初学者在掌握了基本语法后,对于类和对象的深层特性和应用场景仍然存在困惑。今天我们就来深入探讨C++中类和对象的高级用法,帮助大家真正掌握面向对象编程的精髓。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 类的核心特性详解
2.1 构造函数与析构函数进阶
构造函数和析构函数是类的重要组成部分,它们控制着对象的创建和销毁过程。在实际开发中,我们需要掌握它们的各种变体和应用场景。
cpp复制class Person {
public:
// 默认构造函数
Person() : age(0), name("Unknown") {}
// 带参数的构造函数
Person(int a, const string& n) : age(a), name(n) {}
// 拷贝构造函数
Person(const Person& other) : age(other.age), name(other.name) {
cout << "Copy constructor called" << endl;
}
// 移动构造函数(C++11)
Person(Person&& other) noexcept
: age(std::move(other.age)), name(std::move(other.name)) {
cout << "Move constructor called" << endl;
}
// 析构函数
~Person() {
cout << "Destructor called for " << name << endl;
}
private:
int age;
string name;
};
注意:在实现移动构造函数时,一定要加上noexcept关键字,否则在某些容器操作中可能无法使用移动语义。
2.2 运算符重载实战
运算符重载可以让我们的类支持类似内置类型的操作,大大提升代码的可读性和易用性。
cpp复制class Vector {
public:
Vector(int x = 0, int y = 0) : x(x), y(y) {}
// 加法运算符重载
Vector operator+(const Vector& other) const {
return Vector(x + other.x, y + other.y);
}
// 输出运算符重载(通常声明为友元)
friend ostream& operator<<(ostream& os, const Vector& v) {
os << "(" << v.x << ", " << v.y << ")";
return os;
}
// 下标运算符重载
int& operator[](int index) {
if(index == 0) return x;
if(index == 1) return y;
throw out_of_range("Vector index out of range");
}
private:
int x, y;
};
3. 类的继承与多态
3.1 继承体系构建
继承是面向对象编程的三大特性之一,它允许我们基于已有类创建新类,实现代码的复用和扩展。
cpp复制class Shape {
public:
virtual double area() const = 0; // 纯虚函数
virtual ~Shape() {} // 虚析构函数
};
class Circle : public Shape {
public:
Circle(double r) : radius(r) {}
double area() const override {
return 3.14159 * radius * radius;
}
private:
double radius;
};
class Rectangle : public Shape {
public:
Rectangle(double w, double h) : width(w), height(h) {}
double area() const override {
return width * height;
}
private:
double width, height;
};
提示:当基类包含虚函数时,一定要将析构函数也声明为虚函数,否则通过基类指针删除派生类对象时会导致资源泄漏。
3.2 多态的实现原理
多态是面向对象编程的核心概念,它允许我们通过基类接口操作派生类对象。理解多态的实现机制对于编写高效、灵活的代码至关重要。
cpp复制void printArea(const Shape& shape) {
cout << "Area: " << shape.area() << endl;
}
int main() {
Circle c(5.0);
Rectangle r(4.0, 6.0);
printArea(c); // 输出圆的面积
printArea(r); // 输出矩形的面积
return 0;
}
多态的实现依赖于虚函数表(vtable)机制。每个包含虚函数的类都有一个虚函数表,其中存储了虚函数的地址。对象中包含一个指向虚函数表的指针(vptr),通过这个指针可以在运行时确定调用哪个函数。
4. 类的静态成员与友元
4.1 静态成员的应用
静态成员属于类本身而非类的对象,它们在所有对象间共享。静态成员常用于实现类级别的数据和功能。
cpp复制class Counter {
public:
Counter() { ++count; }
~Counter() { --count; }
static int getCount() { return count; }
private:
static int count; // 静态成员变量声明
};
int Counter::count = 0; // 静态成员变量定义
int main() {
Counter c1, c2, c3;
cout << "Current count: " << Counter::getCount() << endl; // 输出3
{
Counter c4;
cout << "Current count: " << Counter::getCount() << endl; // 输出4
}
cout << "Current count: " << Counter::getCount() << endl; // 输出3
return 0;
}
4.2 友元函数与友元类
友元机制打破了类的封装性,允许特定的外部函数或类访问类的私有成员。虽然要谨慎使用,但在某些场景下非常有用。
cpp复制class Matrix;
class Vector {
friend class Matrix; // 声明Matrix为友元类
friend Vector multiply(const Matrix& m, const Vector& v); // 声明友元函数
public:
Vector(double x = 0, double y = 0) : x(x), y(y) {}
private:
double x, y;
};
class Matrix {
public:
Matrix(double a = 0, double b = 0, double c = 0, double d = 0)
: a11(a), a12(b), a21(c), a22(d) {}
Vector transform(const Vector& v) const {
return Vector(a11 * v.x + a12 * v.y, a21 * v.x + a22 * v.y);
}
private:
double a11, a12, a21, a22;
};
Vector multiply(const Matrix& m, const Vector& v) {
return Vector(m.a11 * v.x + m.a12 * v.y, m.a21 * v.x + m.a22 * v.y);
}
5. 类的特殊成员函数
5.1 拷贝控制成员
C++11引入了移动语义,使得类的特殊成员函数更加丰富。理解这些函数的调用时机和实现方式对于编写高效的C++代码至关重要。
cpp复制class ResourceHolder {
public:
// 构造函数
ResourceHolder(size_t size) : size(size), data(new int[size]) {
cout << "Default constructor" << endl;
}
// 拷贝构造函数
ResourceHolder(const ResourceHolder& other) : size(other.size), data(new int[other.size]) {
cout << "Copy constructor" << endl;
std::copy(other.data, other.data + other.size, data);
}
// 移动构造函数
ResourceHolder(ResourceHolder&& other) noexcept
: size(other.size), data(other.data) {
cout << "Move constructor" << endl;
other.size = 0;
other.data = nullptr;
}
// 拷贝赋值运算符
ResourceHolder& operator=(const ResourceHolder& other) {
cout << "Copy assignment" << endl;
if(this != &other) {
delete[] data;
size = other.size;
data = new int[size];
std::copy(other.data, other.data + size, data);
}
return *this;
}
// 移动赋值运算符
ResourceHolder& operator=(ResourceHolder&& other) noexcept {
cout << "Move assignment" << endl;
if(this != &other) {
delete[] data;
size = other.size;
data = other.data;
other.size = 0;
other.data = nullptr;
}
return *this;
}
// 析构函数
~ResourceHolder() {
cout << "Destructor" << endl;
delete[] data;
}
private:
size_t size;
int* data;
};
5.2 类型转换运算符
类型转换运算符允许我们定义类对象到其他类型的隐式或显式转换。
cpp复制class Rational {
public:
Rational(int n = 0, int d = 1) : numerator(n), denominator(d) {}
// 转换为double
explicit operator double() const {
return static_cast<double>(numerator) / denominator;
}
// 转换为bool
explicit operator bool() const {
return numerator != 0;
}
private:
int numerator, denominator;
};
int main() {
Rational r(3, 4);
double d = static_cast<double>(r); // 显式转换
if(r) { // 上下文转换为bool
cout << "r is not zero" << endl;
}
return 0;
}
建议:将类型转换运算符声明为explicit,避免意外的隐式转换导致难以发现的错误。
6. 类的高级特性
6.1 嵌套类与局部类
C++允许在类内部定义其他类,这种嵌套类可以更好地组织代码,实现更强的封装。
cpp复制class LinkedList {
public:
LinkedList() : head(nullptr) {}
void insert(int value) {
head = new Node(value, head);
}
// 嵌套类
class Iterator {
public:
Iterator(Node* p = nullptr) : current(p) {}
int& operator*() const {
return current->data;
}
Iterator& operator++() {
current = current->next;
return *this;
}
bool operator!=(const Iterator& other) const {
return current != other.current;
}
private:
Node* current;
};
Iterator begin() { return Iterator(head); }
Iterator end() { return Iterator(); }
private:
struct Node {
int data;
Node* next;
Node(int d, Node* n) : data(d), next(n) {}
};
Node* head;
};
6.2 类模板
类模板允许我们编写与数据类型无关的通用代码,是C++泛型编程的基础。
cpp复制template <typename T>
class Stack {
public:
Stack() : top(nullptr) {}
~Stack() {
while(!isEmpty()) {
pop();
}
}
void push(const T& value) {
top = new Node(value, top);
}
T pop() {
if(isEmpty()) {
throw std::runtime_error("Stack underflow");
}
T value = top->data;
Node* temp = top;
top = top->next;
delete temp;
return value;
}
bool isEmpty() const {
return top == nullptr;
}
private:
struct Node {
T data;
Node* next;
Node(const T& d, Node* n) : data(d), next(n) {}
};
Node* top;
};
7. 类的设计原则与最佳实践
7.1 RAII原则
资源获取即初始化(RAII)是C++中管理资源的重要原则,它利用对象的生命周期来管理资源。
cpp复制class FileHandle {
public:
explicit FileHandle(const char* filename, const char* mode) {
file = fopen(filename, mode);
if(!file) {
throw std::runtime_error("Failed to open file");
}
}
~FileHandle() {
if(file) {
fclose(file);
}
}
// 禁用拷贝
FileHandle(const FileHandle&) = delete;
FileHandle& operator=(const FileHandle&) = delete;
// 允许移动
FileHandle(FileHandle&& other) noexcept : file(other.file) {
other.file = nullptr;
}
FileHandle& operator=(FileHandle&& other) noexcept {
if(this != &other) {
if(file) fclose(file);
file = other.file;
other.file = nullptr;
}
return *this;
}
FILE* get() const { return file; }
private:
FILE* file;
};
7.2 接口设计原则
良好的类接口设计应该遵循以下原则:
- 最小化接口:只暴露必要的功能
- 高内聚:相关功能组织在一起
- 低耦合:减少类之间的依赖
- 不易误用:使接口难以被错误使用
- 一致性:遵循一致的命名和设计模式
cpp复制// 良好的接口设计示例
class Socket {
public:
// 使用enum代替bool参数,提高可读性
enum class BlockingMode { Blocking, NonBlocking };
explicit Socket(BlockingMode mode = BlockingMode::Blocking);
// 使用RAII管理资源
~Socket();
// 禁用拷贝
Socket(const Socket&) = delete;
Socket& operator=(const Socket&) = delete;
// 允许移动
Socket(Socket&&) noexcept;
Socket& operator=(Socket&&) noexcept;
// 清晰的错误处理
void connect(const std::string& host, uint16_t port);
// 提供足够但不冗余的功能
size_t read(void* buffer, size_t size);
size_t write(const void* data, size_t size);
private:
// 实现细节隐藏
int socket_fd;
BlockingMode mode;
};
8. 常见问题与解决方案
8.1 对象切片问题
当派生类对象被赋值给基类对象时,会发生对象切片,派生类特有的部分会被"切掉"。
cpp复制class Base {
public:
virtual void print() const {
cout << "Base" << endl;
}
};
class Derived : public Base {
public:
void print() const override {
cout << "Derived" << endl;
}
};
void func(Base b) {
b.print(); // 总是调用Base::print()
}
int main() {
Derived d;
func(d); // 输出"Base",发生了对象切片
return 0;
}
解决方案:
- 使用指针或引用传递对象
- 使用智能指针管理对象生命周期
- 将基类声明为抽象类,防止直接实例化
8.2 多继承与菱形继承
多继承可能带来菱形继承问题,导致二义性和资源浪费。
cpp复制class A {
public:
int data;
};
class B : public A {};
class C : public A {};
class D : public B, public C {}; // 菱形继承
int main() {
D d;
// d.data = 10; // 错误:对data的访问不明确
d.B::data = 10; // 需要明确指定路径
d.C::data = 20; // B::data和C::data是不同的副本
cout << d.B::data << endl; // 输出10
cout << d.C::data << endl; // 输出20
return 0;
}
解决方案:
- 使用虚继承
- 尽量避免多继承,优先使用组合
- 使用接口类(纯抽象类)实现多继承
cpp复制class A {
public:
int data;
};
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {}; // 虚继承解决菱形问题
int main() {
D d;
d.data = 10; // 现在可以明确访问
cout << d.data << endl; // 输出10
return 0;
}
9. 现代C++中的类特性
9.1 默认和删除的特殊成员函数
C++11允许我们显式地指定使用默认实现或删除特殊成员函数。
cpp复制class NonCopyable {
public:
NonCopyable() = default;
~NonCopyable() = default;
// 禁用拷贝
NonCopyable(const NonCopyable&) = delete;
NonCopyable& operator=(const NonCopyable&) = delete;
// 允许移动
NonCopyable(NonCopyable&&) = default;
NonCopyable& operator=(NonCopyable&&) = default;
};
9.2 override和final关键字
override和final关键字可以明确表达我们的设计意图,帮助编译器发现错误。
cpp复制class Base {
public:
virtual void func1() const;
virtual void func2(int);
void func3();
virtual ~Base() {}
};
class Derived : public Base {
public:
void func1() const override; // 正确:重写基类虚函数
// void func2(double) override; // 错误:签名不匹配
// void func3() override; // 错误:func3不是虚函数
// final表示禁止进一步重写
void func1() const final {
cout << "Derived::func1" << endl;
}
};
class FurtherDerived : public Derived {
public:
// void func1() const; // 错误:func1在Derived中是final
};
9.3 委托构造函数
C++11引入了委托构造函数,允许一个构造函数调用同类中的另一个构造函数。
cpp复制class Employee {
public:
Employee() : Employee("Unknown", 0) {} // 委托给下面的构造函数
Employee(string name) : Employee(name, 0) {} // 再次委托
Employee(string name, int id) : name(name), id(id) {
// 实际的初始化代码
}
private:
string name;
int id;
};
10. 性能优化与类设计
10.1 返回值优化(RVO)与命名返回值优化(NRVO)
现代编译器通常会进行返回值优化,避免不必要的拷贝。
cpp复制class BigObject {
public:
BigObject() { cout << "Constructor" << endl; }
BigObject(const BigObject&) { cout << "Copy constructor" << endl; }
BigObject(BigObject&&) { cout << "Move constructor" << endl; }
};
BigObject createObject() {
return BigObject(); // 通常会被RVO优化
}
BigObject createNamedObject() {
BigObject obj;
return obj; // 可能被NRVO优化
}
int main() {
BigObject o1 = createObject(); // 通常只调用一次构造函数
BigObject o2 = createNamedObject(); // 可能只调用一次构造函数
return 0;
}
10.2 小对象优化
许多标准库实现(如std::string)会使用小对象优化,避免对小对象进行堆分配。
cpp复制class SmallString {
public:
SmallString(const char* str) {
size_t len = strlen(str);
if(len < sizeof(local_buf)) {
// 使用本地缓冲区
memcpy(local_buf, str, len + 1);
is_local = true;
} else {
// 使用堆分配
heap_buf = new char[len + 1];
memcpy(heap_buf, str, len + 1);
is_local = false;
}
}
~SmallString() {
if(!is_local) {
delete[] heap_buf;
}
}
private:
union {
char* heap_buf;
char local_buf[16];
};
bool is_local;
};
11. 类的测试与调试
11.1 单元测试框架集成
为类编写单元测试是保证代码质量的重要手段。下面展示如何使用Catch2测试框架测试我们的类。
cpp复制#define CATCH_CONFIG_MAIN
#include "catch.hpp"
class Calculator {
public:
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
};
TEST_CASE("Calculator operations", "[calculator]") {
Calculator calc;
SECTION("Addition") {
REQUIRE(calc.add(2, 3) == 5);
REQUIRE(calc.add(-1, 1) == 0);
}
SECTION("Subtraction") {
REQUIRE(calc.subtract(5, 3) == 2);
REQUIRE(calc.subtract(3, 5) == -2);
}
}
11.2 调试技巧
调试类相关问题时,以下技巧可能会很有帮助:
- 在构造函数和析构函数中添加打印语句,跟踪对象生命周期
- 使用gdb或lldb等调试器设置断点
- 对于多态类,可以使用typeid或dynamic_cast检查对象类型
- 使用valgrind检测内存泄漏
- 对于模板类,注意编译器错误通常很长,需要耐心阅读
cpp复制class Debuggable {
public:
Debuggable() {
cout << "Constructing Debuggable at " << this << endl;
}
~Debuggable() {
cout << "Destructing Debuggable at " << this << endl;
}
void* operator new(size_t size) {
void* p = ::operator new(size);
cout << "Allocated " << size << " bytes at " << p << endl;
return p;
}
void operator delete(void* p) {
cout << "Deallocating memory at " << p << endl;
::operator delete(p);
}
};
12. 实际应用案例
12.1 实现一个简单的智能指针
让我们实现一个简化版的std::unique_ptr来巩固所学知识。
cpp复制template <typename T>
class UniquePtr {
public:
explicit UniquePtr(T* ptr = nullptr) : ptr(ptr) {}
~UniquePtr() {
delete ptr;
}
// 禁用拷贝
UniquePtr(const UniquePtr&) = delete;
UniquePtr& operator=(const UniquePtr&) = delete;
// 允许移动
UniquePtr(UniquePtr&& other) noexcept : ptr(other.ptr) {
other.ptr = nullptr;
}
UniquePtr& operator=(UniquePtr&& other) noexcept {
if(this != &other) {
delete ptr;
ptr = other.ptr;
other.ptr = nullptr;
}
return *this;
}
T& operator*() const { return *ptr; }
T* operator->() const { return ptr; }
explicit operator bool() const { return ptr != nullptr; }
T* get() const { return ptr; }
T* release() {
T* temp = ptr;
ptr = nullptr;
return temp;
}
void reset(T* p = nullptr) {
delete ptr;
ptr = p;
}
private:
T* ptr;
};
12.2 实现一个线程安全的队列
结合类和线程,我们可以实现一个线程安全的队列。
cpp复制#include <queue>
#include <mutex>
#include <condition_variable>
template <typename T>
class ThreadSafeQueue {
public:
void push(const T& value) {
{
std::lock_guard<std::mutex> lock(mutex);
queue.push(value);
}
cond.notify_one();
}
bool try_pop(T& value) {
std::lock_guard<std::mutex> lock(mutex);
if(queue.empty()) {
return false;
}
value = queue.front();
queue.pop();
return true;
}
void wait_and_pop(T& value) {
std::unique_lock<std::mutex> lock(mutex);
cond.wait(lock, [this]{ return !queue.empty(); });
value = queue.front();
queue.pop();
}
bool empty() const {
std::lock_guard<std::mutex> lock(mutex);
return queue.empty();
}
private:
mutable std::mutex mutex;
std::queue<T> queue;
std::condition_variable cond;
};
13. C++20中的类新特性
13.1 三向比较运算符
C++20引入了三向比较运算符(<=>),简化了比较运算符的实现。
cpp复制class Point {
public:
Point(int x, int y) : x(x), y(y) {}
auto operator<=>(const Point& other) const = default;
private:
int x, y;
};
int main() {
Point p1(1, 2), p2(3, 4);
if(p1 < p2) {
cout << "p1 is less than p2" << endl;
}
return 0;
}
13.2 概念(Concepts)与类模板
概念(Concepts)是C++20引入的重要特性,它可以对模板参数施加约束。
cpp复制template <typename T>
concept Addable = requires(T a, T b) {
{ a + b } -> std::same_as<T>;
};
template <Addable T>
class Calculator {
public:
T add(T a, T b) { return a + b; }
};
14. 跨平台开发中的类设计
14.1 PImpl惯用法
PImpl(Pointer to Implementation)是一种减少编译依赖和提高封装性的技术。
cpp复制// Widget.h
class Widget {
public:
Widget();
~Widget();
void doSomething();
private:
struct Impl;
std::unique_ptr<Impl> pImpl;
};
// Widget.cpp
struct Widget::Impl {
void privateMethod() {
// 实现细节
}
int data;
std::string name;
};
Widget::Widget() : pImpl(std::make_unique<Impl>()) {}
Widget::~Widget() = default; // 需要看到Impl的完整定义
void Widget::doSomething() {
pImpl->privateMethod();
// 使用pImpl->data等
}
14.2 条件编译与平台特定代码
在跨平台开发中,我们经常需要编写平台特定的代码。使用类可以很好地组织这些代码。
cpp复制class FileSystem {
public:
static std::string getHomeDirectory() {
#ifdef _WIN32
return getWindowsHomeDir();
#else
return getUnixHomeDir();
#endif
}
private:
#ifdef _WIN32
static std::string getWindowsHomeDir() {
// Windows实现
}
#else
static std::string getUnixHomeDir() {
// Unix实现
}
#endif
};
15. 类设计模式实战
15.1 单例模式实现
单例模式确保一个类只有一个实例,并提供一个全局访问点。
cpp复制class Singleton {
public:
static Singleton& getInstance() {
static Singleton instance;
return instance;
}
void doSomething() {
cout << "Singleton operation" << endl;
}
// 禁用拷贝和移动
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(Singleton&&) = delete;
private:
Singleton() = default;
~Singleton() = default;
};
15.2 工厂模式实现
工厂模式提供了一种创建对象的方式,而无需指定具体类。
cpp复制class Shape {
public:
virtual ~Shape() = default;
virtual void draw() const = 0;
};
class Circle : public Shape {
public:
void draw() const override {
cout << "Drawing Circle" << endl;
}
};
class Rectangle : public Shape {
public:
void draw() const override {
cout << "Drawing Rectangle" << endl;
}
};
class ShapeFactory {
public:
enum class Type { Circle, Rectangle };
static std::unique_ptr<Shape> create(Type type) {
switch(type) {
case Type::Circle: return std::make_unique<Circle>();
case Type::Rectangle: return std::make_unique<Rectangle>();
default: throw std::invalid_argument("Unknown shape type");
}
}
};
16. 类与STL的集成
16.1 自定义STL兼容容器
要让自定义容器与STL算法兼容,需要提供适当的迭代器和类型定义。
cpp复制template <typename T>
class SimpleVector {
public:
// STL容器需要的类型定义
using value_type = T;
using reference = T&;
using const_reference = const T&;
using iterator = T*;
using const_iterator = const T*;
using size_type = size_t;
SimpleVector(size_type size = 0) : data(new T[size]), size(size) {}
~SimpleVector() { delete[] data; }
iterator begin() { return data; }
iterator end() { return data + size; }
const_iterator begin() const { return data; }
const_iterator end() const { return data + size; }
reference operator[](size_type index) { return data[index]; }
const_reference operator[](size_type index) const { return data[index]; }
size_type size() const { return size; }
private:
T* data;
size_type size;
};
16.2 自定义分配器
STL容器允许我们自定义内存分配策略,这在某些特殊场景下非常有用。
cpp复制template <typename T>
class PoolAllocator {
public:
using value_type = T;
PoolAllocator() = default;
template <typename U>
PoolAllocator(const PoolAllocator<U>&) {}
T* allocate(size_t n) {
cout << "Allocating " << n << " objects" << endl;
return static_cast<T*>(::operator new(n * sizeof(T)));
}
void deallocate(T* p, size_t n) {
cout << "Deallocating " << n << " objects" << endl;
::operator delete(p);
}
};
template <typename T, typename U>
bool operator==(const PoolAllocator<T>&, const PoolAllocator<U>&) {
return true;
}
template <typename T, typename U>
bool operator!=(const PoolAllocator<T>&, const PoolAllocator<U>&) {
return false;
}
17. 类与元编程
17.1 类型特征与SFINAE
利用模板元编程,我们可以在编译时对类型进行检测和操作。
cpp复制template <typename T>
class IsPointer {
template <typename U>
static std::true_type test(U*);
static std::false_type test(...);
public:
static constexpr bool value = decltype(test(std::declval<T>()))::value;
};
template <typename T>
void printPointer(T ptr) {
if constexpr(IsPointer<T>::value) {
cout << *ptr << endl;
} else {
cout << ptr << endl;
}
}
17.2 CRTP模式
奇异递归模板模式(CRTP)是一种静态多态技术。
cpp复制template <typename Derived>
class Base {
public:
void interface() {
static_cast<Derived*>(this)->implementation();
}
};
class Derived : public Base<Derived> {
public:
void implementation() {
cout << "Derived implementation" << endl;
}
};
template <typename T>
void doSomething(Base<T>& obj) {
obj.interface();
}
18. 类与并发编程
18.1 线程安全的单例
实现一个线程安全的单例模式需要考虑多线程环境下的初始化问题。
cpp复制class ThreadSafeSingleton {
public:
static ThreadSafeSingleton& getInstance() {
std::call_once(initFlag, []() {
instance.reset(new ThreadSafeSingleton);
});
return *instance;
}
void doSomething() {
cout << "Thread-safe singleton operation" << endl;
}
private:
ThreadSafeSingleton() = default;
~ThreadSafeSingleton() = default;
static std::unique_ptr<ThreadSafeSingleton> instance;
static std::once_flag initFlag;
};
std::unique_ptr<ThreadSafeSingleton> ThreadSafeSingleton::instance;
std::once_flag ThreadSafeSingleton::initFlag;
18.2 原子操作与类
C++11引入的原子类型可以帮助我们实现无锁数据结构。
cpp复制class AtomicCounter {
public:
void increment() {
count.fetch_add(1, std::memory_order_relaxed);
}
void decrement() {
count.fetch_sub(1, std::memory_order_relaxed);
}
int get() const {
return count.load(std::memory_order_relaxed);
}
private:
std::atomic<int> count{0};
};
19. 类与移动语义
19.1 移动语义的最佳实践
理解移动语义对于编写高效的现代C++代码至关重要。
cpp复制class Resource {
public:
Resource(size_t size) : size(size), data(new int[size]) {}
// 移动构造函数
Resource(Resource&& other) noexcept
: size(other.size), data(other.data) {
other.size = 0;
other.data = nullptr;
}
// 移动赋值运算符
Resource& operator=(Resource&& other) noexcept {
if(this != &other) {
delete[] data;
size = other.size;
data = other.data;
other.size = 0;
other.data = nullptr;
}
return *this;
}
~Resource() {
delete[] data;
}
private:
size_t size;
int* data;
};
19.2 完美转发
完美转发允许我们保持参数的左值/右值属性。
cpp复制class Wrapper {
public:
template <typename T>
Wrapper(T&& arg) : arg(std::forward<T>(arg)) {}
void process() {
// 处理arg
}
private:
SomeType arg;
};
20. 类设计的高级话题
20.1 类型擦除技术
类型擦除允许我们在不丢失类型安全的情况下处理多种类型。
cpp复制class AnyDrawable {
struct Concept {
virtual ~Concept() = default;
virtual void draw() const = 0;
};
template <typename T>
struct Model : Concept {
Model(T value) : value(std::move(value)) {}
void draw() const override { value.draw(); }
T value;
};
std::unique_ptr<Concept> pimpl;
public:
template <typename T>
AnyDrawable(T value) : pimpl(std::make_unique<Model<T>>(std::move(value))) {}
void draw() const {
if(pimpl) pimpl->draw();
}
};
20.2 策略模式与类设计
策略模式允许在运行时选择算法或行为。
cpp复制class SortingStrategy {
public:
virtual ~SortingStrategy() = default;
virtual void sort(std::vector<int>& data) const = 0;
};
class QuickSort : public SortingStrategy {
public:
void sort(std::vector<int>& data) const override {
cout << "Sorting with QuickSort" << endl;
// 实际实现
}
};
class MergeSort : public SortingStrategy {
public:
void sort(std::vector<int>& data) const override {
cout << "Sorting with MergeSort" << endl;
// 实际实现
}
};
class Sorter {
std::unique_ptr<SortingStrategy> strategy;
public:
explicit Sorter(std::unique_ptr<SortingStrategy> strategy)
: strategy(std::move(strategy)) {}
void setStrategy(std::unique_ptr<SortingStrategy> newStrategy) {
strategy = std::move(newStrategy);
}
void do
