C++ 入门指南 (Java开发者版)

7 阅读28分钟

C++ 入门指南 (Java开发者版)

目录

  1. 基础语法对比
  2. 内存管理
  3. 面向对象编程
  4. 标准库
  5. 编译与构建
  6. 常见陷阱与最佳实践

基础语法对比

1. 基本类型

JavaC++说明
booleanbool布尔类型
bytechar8位整数
shortshort16位整数
intint32位整数
longlong long64位整数
floatfloat32位浮点数
doubledouble64位浮点数
Stringstd::string字符串类型

2. 变量声明与初始化

Java:

int x = 10;
final int y = 20;  // 常量

C++:

int x = 10;
const int y = 20;  // 常量
auto z = 30;       // 类型推导

3. 引用与指针

Java中只有引用,而C++同时支持引用和指针:

// 引用
int x = 10;
int& ref = x;      // 引用必须初始化
ref = 20;          // x也变成20

// 指针
int* ptr = &x;     // 获取x的地址
*ptr = 30;         // 通过指针修改x的值

内存管理

1. 栈与堆

Java中所有对象都在堆上分配,而C++允许在栈上创建对象:

// 栈上分配
MyClass obj1;              // 自动管理内存

// 堆上分配
MyClass* obj2 = new MyClass();    // 需要手动释放
delete obj2;                      // 手动释放内存

2. 智能指针

C++11引入了智能指针,类似于Java的垃圾回收:

#include <memory>

// 独占所有权
std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>();

// 共享所有权
std::shared_ptr<MyClass> ptr2 = std::make_shared<MyClass>();

面向对象编程

1. 类定义

Java:

public class MyClass {
    private int x;
    public MyClass(int x) {
        this.x = x;
    }
}

C++:

class MyClass {
private:
    int x;
public:
    MyClass(int x) : x(x) {}  // 初始化列表
};

2. 继承

Java:

public class Child extends Parent {
    public Child() {
        super();
    }
}

C++:

class Child : public Parent {
public:
    Child() : Parent() {}  // 调用父类构造函数
};

3. 虚函数

Java中所有方法默认都是虚函数,C++需要显式声明:

class Base {
public:
    virtual void foo() = 0;  // 纯虚函数
    virtual ~Base() {}       // 虚析构函数
};

标准库

1. 容器

JavaC++说明
ArrayListstd::vector动态数组
LinkedListstd::list双向链表
HashMapstd::unordered_map哈希表
TreeMapstd::map有序映射

使用示例:

#include <vector>
#include <map>

std::vector<int> vec = {1, 2, 3};
std::map<std::string, int> map;
map["key"] = 42;

2. 算法

C++标准库提供了丰富的算法:

#include <algorithm>

std::vector<int> vec = {3, 1, 4, 1, 5};
std::sort(vec.begin(), vec.end());
auto it = std::find(vec.begin(), vec.end(), 4);

编译与构建

1. 编译过程

C++需要显式编译,而Java是解释执行:

# 编译
g++ -std=c++17 main.cpp -o program

# 运行
./program

2. 头文件

C++使用头文件声明接口:

// myclass.h
class MyClass {
public:
    void foo();
};

// myclass.cpp
#include "myclass.h"
void MyClass::foo() {
    // 实现
}

常见陷阱与最佳实践

1. 内存泄漏

避免使用原始指针,优先使用智能指针:

// 不推荐
MyClass* ptr = new MyClass();
// 可能忘记delete

// 推荐
auto ptr = std::make_unique<MyClass>();
// 自动管理内存

2. 字符串处理

使用std::string而不是C风格字符串:

// 不推荐
char* str = "Hello";

// 推荐
std::string str = "Hello";

3. 现代C++特性

优先使用现代C++特性:

// 范围for循环
for (const auto& item : container) {
    // 处理item
}

// lambda表达式
auto add = [](int a, int b) { return a + b; };

C++特有特性

1. 友元函数和友元类

C++允许非成员函数或类访问类的私有成员:

class MyClass {
private:
    int secret;
    
    // 声明友元函数
    friend void friendFunction(MyClass& obj);
    
    // 声明友元类
    friend class FriendClass;
};

// 友元函数实现
void friendFunction(MyClass& obj) {
    obj.secret = 42;  // 可以直接访问私有成员
}

class FriendClass {
public:
    void accessSecret(MyClass& obj) {
        obj.secret = 100;  // 可以直接访问私有成员
    }
};

2. 运算符重载

C++允许重载运算符,使自定义类型支持运算符操作:

class Complex {
private:
    double real, imag;
public:
    Complex(double r, double i) : real(r), imag(i) {}
    
    // 重载+运算符
    Complex operator+(const Complex& other) const {
        return Complex(real + other.real, imag + other.imag);
    }
    
    // 重载输出运算符
    friend std::ostream& operator<<(std::ostream& os, const Complex& c) {
        os << c.real << " + " << c.imag << "i";
        return os;
    }
};

// 使用示例
Complex c1(1, 2), c2(3, 4);
Complex c3 = c1 + c2;  // 使用重载的+运算符
std::cout << c3;       // 使用重载的<<运算符

3. 模板编程

C++的模板系统比Java的泛型更强大:

// 函数模板
template<typename T>
T max(T a, T b) {
    return (a > b) ? a : b;
}

// 类模板
template<typename T>
class Stack {
private:
    std::vector<T> elements;
public:
    void push(T const& elem) {
        elements.push_back(elem);
    }
    T pop() {
        T elem = elements.back();
        elements.pop_back();
        return elem;
    }
};

// 使用示例
int i = max(10, 20);                    // 使用int类型
double d = max(3.14, 2.72);             // 使用double类型
Stack<int> intStack;                    // 整数栈
Stack<std::string> stringStack;         // 字符串栈

4. 移动语义和右值引用

C++11引入的移动语义可以优化性能:

class Resource {
private:
    int* data;
public:
    // 移动构造函数
    Resource(Resource&& other) noexcept : data(other.data) {
        other.data = nullptr;
    }
    
    // 移动赋值运算符
    Resource& operator=(Resource&& other) noexcept {
        if (this != &other) {
            delete data;
            data = other.data;
            other.data = nullptr;
        }
        return *this;
    }
};

// 使用示例
Resource r1;
Resource r2 = std::move(r1);  // 使用移动语义

5. 命名空间

C++使用命名空间来组织代码:

namespace MyLib {
    class MyClass {
        // ...
    };
    
    void myFunction() {
        // ...
    }
}

// 使用方式
MyLib::MyClass obj;
MyLib::myFunction();

// 或者使用using声明
using namespace MyLib;
MyClass obj;
myFunction();

6. 预处理器指令

C++的预处理器提供了强大的编译时功能:

// 条件编译
#ifdef DEBUG
    #define LOG(x) std::cout << x << std::endl
#else
    #define LOG(x)
#endif

// 防止头文件重复包含
#ifndef MY_HEADER_H
#define MY_HEADER_H
    // 头文件内容
#endif

// 内联函数
inline int square(int x) {
    return x * x;
}

7. 异常处理

C++的异常处理机制:

class MyException : public std::exception {
public:
    const char* what() const noexcept override {
        return "My custom exception";
    }
};

void riskyFunction() {
    throw MyException();
}

// 使用示例
try {
    riskyFunction();
} catch (const MyException& e) {
    std::cerr << e.what() << std::endl;
} catch (const std::exception& e) {
    std::cerr << "Standard exception: " << e.what() << std::endl;
} catch (...) {
    std::cerr << "Unknown exception" << std::endl;
}

8. 函数对象和Lambda表达式

C++支持函数式编程特性:

// 函数对象
class Adder {
private:
    int value;
public:
    Adder(int v) : value(v) {}
    int operator()(int x) const {
        return x + value;
    }
};

// Lambda表达式
auto multiply = [](int x, int y) { return x * y; };
auto add = [value = 10](int x) { return x + value; };

// 使用示例
Adder add5(5);
int result1 = add5(10);        // 15
int result2 = multiply(3, 4);  // 12
int result3 = add(5);          // 15

9. 多重继承和虚继承

C++支持多重继承,这是Java所没有的特性:

// 普通多重继承
class Animal {
public:
    virtual void eat() = 0;
};

class Flying {
public:
    virtual void fly() = 0;
};

class Bird : public Animal, public Flying {
public:
    void eat() override { /* 实现 */ }
    void fly() override { /* 实现 */ }
};

// 虚继承(解决菱形继承问题)
class Base {
public:
    int value;
};

class Derived1 : virtual public Base {};
class Derived2 : virtual public Base {};

class Final : public Derived1, public Derived2 {
    // 只有一个value成员
};

10. 类型转换

C++提供了多种类型转换方式:

// 1. C风格转换(不推荐)
int i = (int)3.14;

// 2. static_cast:编译时类型检查
double d = 3.14;
int i = static_cast<int>(d);

// 3. dynamic_cast:运行时类型检查(用于多态)
Base* base = new Derived();
Derived* derived = dynamic_cast<Derived*>(base);

// 4. const_cast:移除const属性
const int* p = &i;
int* q = const_cast<int*>(p);

// 5. reinterpret_cast:底层位模式转换
int* p = reinterpret_cast<int*>(0x1234);

11. 可变参数模板

C++支持可变参数模板,比Java的变长参数更强大:

// 可变参数函数模板
template<typename... Args>
void print(Args... args) {
    (std::cout << ... << args) << std::endl;
}

// 可变参数类模板
template<typename... Types>
class Tuple;

template<typename Head, typename... Tail>
class Tuple<Head, Tail...> : public Tuple<Tail...> {
    Head head;
public:
    Tuple(Head h, Tail... t) : Tuple<Tail...>(t...), head(h) {}
};

// 使用示例
print(1, "hello", 3.14);  // 打印多个参数
Tuple<int, string, double> t(1, "hello", 3.14);

12. 完美转发

C++11引入的完美转发可以保持参数的值类别:

template<typename T>
void wrapper(T&& arg) {
    foo(std::forward<T>(arg));  // 完美转发
}

// 使用示例
wrapper(42);              // 右值
int x = 42;
wrapper(x);              // 左值
wrapper(std::move(x));   // 右值

13. constexpr和编译期计算

C++支持在编译期进行计算:

// constexpr函数
constexpr int factorial(int n) {
    return (n <= 1) ? 1 : (n * factorial(n - 1));
}

// constexpr变量
constexpr int max_size = 100;

// 编译期计算
constexpr int result = factorial(10);  // 在编译期计算

// if constexpr(C++17)
template<typename T>
auto getValue(T t) {
    if constexpr (std::is_integral_v<T>) {
        return t * 2;
    } else {
        return t;
    }
}

14. 并发编程

C++11引入了标准线程库:

#include <thread>
#include <mutex>
#include <future>

// 线程
void threadFunction() {
    // 线程代码
}

std::thread t(threadFunction);
t.join();

// 互斥锁
std::mutex mtx;
{
    std::lock_guard<std::mutex> lock(mtx);
    // 临界区
}

// 异步任务
auto future = std::async(std::launch::async, []() {
    return 42;
});
int result = future.get();

15. 内存模型和原子操作

C++11引入了内存模型和原子操作:

#include <atomic>

std::atomic<int> counter{0};

void increment() {
    counter.fetch_add(1, std::memory_order_relaxed);
}

// 内存序
std::atomic<int> x{0}, y{0};
void thread1() {
    x.store(1, std::memory_order_release);
    y.store(1, std::memory_order_release);
}

void thread2() {
    while (y.load(std::memory_order_acquire) != 1);
    assert(x.load(std::memory_order_acquire) == 1);
}

16. 概念(Concepts)和约束

C++20引入的概念系统提供了更强大的模板约束:

// 定义概念
template<typename T>
concept Number = std::is_arithmetic_v<T>;

// 使用概念约束
template<Number T>
T add(T a, T b) {
    return a + b;
}

// 组合概念
template<typename T>
concept Sortable = requires(T a) {
    { a < a } -> std::convertible_to<bool>;
    { std::sort(&a, &a) };
};

// 使用示例
template<Sortable T>
void sortContainer(T& container) {
    std::sort(container.begin(), container.end());
}

17. 协程(Coroutines)

C++20引入的协程支持异步编程:

#include <coroutine>
#include <future>

// 定义协程返回类型
struct Task {
    struct promise_type {
        Task get_return_object() { return {}; }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void return_void() {}
        void unhandled_exception() {}
    };
};

// 异步函数
Task asyncFunction() {
    co_await std::suspend_never{};
    // 异步操作
}

18. 模块(Modules)

C++20引入的模块系统提供了更好的代码组织方式:

// math.cppm
module;
#include <cmath>

export module math;

export namespace math {
    double square(double x) { return x * x; }
    double cube(double x) { return x * x * x; }
}

// main.cpp
import math;
import <iostream>;

int main() {
    std::cout << math::square(5) << std::endl;
    return 0;
}

19. 反射(Reflection)

C++23计划引入的反射特性:

// 类型反射
template<typename T>
void printTypeInfo() {
    std::cout << "Type name: " << type_name<T>() << std::endl;
    std::cout << "Size: " << sizeof(T) << std::endl;
    std::cout << "Alignment: " << alignof(T) << std::endl;
}

// 成员反射
template<typename T>
void printMembers(const T& obj) {
    for_each_member(obj, [](auto name, auto value) {
        std::cout << name << ": " << value << std::endl;
    });
}

20. 高级元编程技巧

// 1. SFINAE (Substitution Failure Is Not An Error)
template<typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
increment(T x) {
    return x + 1;
}

// 2. 类型特征
template<typename T>
struct is_container {
    static constexpr bool value = 
        requires(T t) {
            t.begin();
            t.end();
            t.size();
        };
};

// 3. 完美转发
template<typename... Args>
void wrapper(Args&&... args) {
    foo(std::forward<Args>(args)...);
}

// 4. 变参模板展开
template<typename... Args>
void print(Args&&... args) {
    (std::cout << ... << args) << std::endl;
}

21. 内存管理高级特性

// 1. 自定义分配器
template<typename T>
class MyAllocator {
public:
    using value_type = T;
    
    T* allocate(std::size_t n) {
        return static_cast<T*>(::operator new(n * sizeof(T)));
    }
    
    void deallocate(T* p, std::size_t n) {
        ::operator delete(p);
    }
};

// 2. 内存池
class MemoryPool {
    std::vector<char> memory;
    std::size_t used = 0;
public:
    void* allocate(std::size_t size) {
        if (used + size > memory.size()) {
            throw std::bad_alloc();
        }
        void* ptr = &memory[used];
        used += size;
        return ptr;
    }
};

// 3. 智能指针自定义删除器
auto deleter = [](int* p) {
    std::cout << "Deleting " << *p << std::endl;
    delete p;
};
std::unique_ptr<int, decltype(deleter)> ptr(new int(42), deleter);

22. 并发编程高级特性

// 1. 原子操作
std::atomic<int> counter{0};
counter.fetch_add(1, std::memory_order_relaxed);

// 2. 内存序
std::atomic<int> x{0}, y{0};
void thread1() {
    x.store(1, std::memory_order_release);
    y.store(1, std::memory_order_release);
}

// 3. 条件变量
std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void waitForReady() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, []{ return ready; });
}

// 4. 读写锁
std::shared_mutex rwMutex;
void read() {
    std::shared_lock lock(rwMutex);
    // 读取操作
}
void write() {
    std::unique_lock lock(rwMutex);
    // 写入操作
}

实际开发中的最佳实践

1. 代码组织

// 头文件组织
// myproject/
//   ├── include/           // 公共头文件
//   │   └── myproject/
//   │       ├── core.h
//   │       └── utils.h
//   ├── src/              // 源文件
//   │   ├── core.cpp
//   │   └── utils.cpp
//   ├── tests/            // 测试文件
//   └── CMakeLists.txt    // 构建配置

// 头文件保护
#ifndef MYPROJECT_CORE_H
#define MYPROJECT_CORE_H

namespace myproject {
    class Core {
        // ...
    };
}

#endif

2. 错误处理策略

// 1. 异常处理
class DatabaseError : public std::runtime_error {
public:
    explicit DatabaseError(const std::string& msg) 
        : std::runtime_error(msg) {}
};

// 2. 错误码
enum class ErrorCode {
    Success,
    FileNotFound,
    PermissionDenied,
    // ...
};

// 3. 可选值(C++17)
std::optional<int> findValue(const std::vector<int>& vec, int target) {
    auto it = std::find(vec.begin(), vec.end(), target);
    if (it != vec.end()) {
        return *it;
    }
    return std::nullopt;
}

// 4. 预期值(C++23)
std::expected<int, std::string> divide(int a, int b) {
    if (b == 0) {
        return std::unexpected("Division by zero");
    }
    return a / b;
}

3. 性能优化技巧

// 1. 移动语义优化
class Resource {
    std::vector<int> data;
public:
    // 移动构造函数
    Resource(Resource&& other) noexcept 
        : data(std::move(other.data)) {}
    
    // 移动赋值运算符
    Resource& operator=(Resource&& other) noexcept {
        if (this != &other) {
            data = std::move(other.data);
        }
        return *this;
    }
};

// 2. 内联函数
inline int square(int x) {
    return x * x;
}

// 3. 编译期计算
constexpr int fibonacci(int n) {
    return (n <= 1) ? n : fibonacci(n-1) + fibonacci(n-2);
}

// 4. 内存对齐
struct alignas(16) AlignedStruct {
    double x;
    double y;
};

4. 调试技巧

// 1. 断言
#include <cassert>
void process(int* ptr) {
    assert(ptr != nullptr && "Pointer cannot be null");
    // ...
}

// 2. 日志
#include <iostream>
#define LOG_LEVEL 1

#define LOG(level, msg) \
    if (level <= LOG_LEVEL) \
        std::cout << "[" << level << "] " << msg << std::endl

// 3. 调试宏
#ifdef DEBUG
    #define DBG_PRINT(x) std::cout << #x << " = " << x << std::endl
#else
    #define DBG_PRINT(x)
#endif

5. 测试框架使用

// 使用Google Test框架
#include <gtest/gtest.h>

TEST(MyTest, BasicTest) {
    EXPECT_EQ(2 + 2, 4);
    EXPECT_TRUE(true);
    EXPECT_FALSE(false);
}

// 参数化测试
class MyTest : public ::testing::TestWithParam<int> {};

TEST_P(MyTest, ParamTest) {
    int value = GetParam();
    EXPECT_GT(value, 0);
}

INSTANTIATE_TEST_SUITE_P(
    Values, MyTest,
    ::testing::Values(1, 2, 3, 4, 5)
);

6. 构建系统

# CMakeLists.txt 示例
cmake_minimum_required(VERSION 3.10)
project(MyProject)

# 设置C++标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 添加可执行文件
add_executable(myapp src/main.cpp)

# 添加库
add_library(mylib src/lib.cpp)

# 链接库
target_link_libraries(myapp PRIVATE mylib)

# 添加测试
enable_testing()
add_subdirectory(tests)

7. 代码质量工具

# 1. 代码格式化 (clang-format)
clang-format -i *.cpp *.h

# 2. 静态分析 (clang-tidy)
clang-tidy *.cpp -checks=*

# 3. 内存检查 (valgrind)
valgrind --leak-check=full ./myapp

# 4. 性能分析 (gprof)
g++ -pg myapp.cpp -o myapp
./myapp
gprof myapp gmon.out > analysis.txt

学习资源

  1. C++ Reference
  2. C++ Core Guidelines
  3. LearnCpp

总结

从Java转向C++需要注意以下几点:

  1. 理解内存管理:从自动垃圾回收转向手动/智能指针管理
  2. 掌握指针和引用:这是C++的核心概念
  3. 熟悉标准库:特别是STL容器和算法
  4. 注意编译过程:理解头文件、链接等概念
  5. 采用现代C++:使用C++11及以后版本的新特性
  6. 学习C++特有特性:友元、运算符重载、模板等
  7. 理解移动语义:这是现代C++性能优化的关键
  8. 掌握预处理器:了解条件编译和宏定义的使用
  9. 理解多重继承:这是C++特有的面向对象特性
  10. 掌握类型转换:了解各种类型转换的适用场景
  11. 学习并发编程:理解C++的线程模型和内存模型
  12. 重视编译期计算:利用constexpr提高运行时性能
  13. 注重代码质量:使用静态分析工具和测试框架
  14. 掌握构建系统:理解CMake等构建工具的使用
  15. 重视性能优化:合理使用移动语义和编译期计算
  16. 了解新特性:掌握C++20/23引入的概念、协程、模块等
  17. 深入元编程:理解SFINAE、类型特征等高级特性
  18. 掌握内存管理:了解自定义分配器和内存池
  19. 精通并发:理解原子操作、内存序和同步原语
  20. 关注发展:跟踪C++标准的发展和新特性

记住:C++给予你更多的控制权,但也需要更多的责任。正确使用C++的特性可以写出高效且安全的代码。在实际开发中,要注意代码组织、错误处理、性能优化和调试技巧,这些都是成为优秀C++开发者的关键。同时,要持续关注C++标准的发展,及时掌握新特性,这样才能写出更现代、更高效的C++代码。

C++面试题精选

1. 基础概念题

1.1 内存管理
// 问题:以下代码有什么问题?
void func() {
    int* ptr = new int[10];
    // ... 使用ptr
    return;  // 内存泄漏
}

// 解答:应该使用智能指针或确保释放内存
void func() {
    std::unique_ptr<int[]> ptr(new int[10]);
    // ... 使用ptr
    // 自动释放内存
}
1.2 指针和引用
// 问题:以下代码输出什么?
int a = 10;
int& ref = a;
int* ptr = &a;
ref = 20;
*ptr = 30;
std::cout << a << std::endl;  // 输出:30

// 问题:以下代码有什么问题?
int& func() {
    int x = 10;
    return x;  // 返回局部变量的引用
}
1.3 虚函数和多态
// 问题:以下代码输出什么?
class Base {
public:
    virtual void foo() { std::cout << "Base" << std::endl; }
    virtual ~Base() {}
};

class Derived : public Base {
public:
    void foo() override { std::cout << "Derived" << std::endl; }
};

Base* ptr = new Derived();
ptr->foo();  // 输出:Derived
delete ptr;

2. 算法和数据结构题

2.1 实现智能指针
// 问题:实现一个简单的智能指针
template<typename T>
class SmartPtr {
    T* ptr;
public:
    SmartPtr(T* p = nullptr) : ptr(p) {}
    ~SmartPtr() { delete ptr; }
    
    T& operator*() { return *ptr; }
    T* operator->() { return ptr; }
    
    // 禁用拷贝
    SmartPtr(const SmartPtr&) = delete;
    SmartPtr& operator=(const SmartPtr&) = delete;
    
    // 允许移动
    SmartPtr(SmartPtr&& other) : ptr(other.ptr) {
        other.ptr = nullptr;
    }
};
2.2 实现线程安全的单例
// 问题:实现线程安全的单例模式
class Singleton {
private:
    static std::atomic<Singleton*> instance;
    static std::mutex mutex;
    
    Singleton() {}
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    
public:
    static Singleton* getInstance() {
        Singleton* p = instance.load(std::memory_order_acquire);
        if (!p) {
            std::lock_guard<std::mutex> lock(mutex);
            p = instance.load(std::memory_order_relaxed);
            if (!p) {
                p = new Singleton();
                instance.store(p, std::memory_order_release);
            }
        }
        return p;
    }
};

3. 系统设计题

3.1 实现线程池
// 问题:实现一个简单的线程池
class ThreadPool {
    std::vector<std::thread> workers;
    std::queue<std::function<void()>> tasks;
    std::mutex queue_mutex;
    std::condition_variable condition;
    bool stop;
    
public:
    ThreadPool(size_t threads) : stop(false) {
        for(size_t i = 0; i < threads; ++i)
            workers.emplace_back([this] {
                while(true) {
                    std::function<void()> task;
                    {
                        std::unique_lock<std::mutex> lock(queue_mutex);
                        condition.wait(lock, [this] {
                            return stop || !tasks.empty();
                        });
                        if(stop && tasks.empty()) return;
                        task = std::move(tasks.front());
                        tasks.pop();
                    }
                    task();
                }
            });
    }
    
    template<class F>
    void enqueue(F&& f) {
        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            tasks.emplace(std::forward<F>(f));
        }
        condition.notify_one();
    }
    
    ~ThreadPool() {
        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            stop = true;
        }
        condition.notify_all();
        for(std::thread &worker: workers)
            worker.join();
    }
};
3.2 实现内存池
// 问题:实现一个简单的内存池
class MemoryPool {
    struct Block {
        Block* next;
    };
    
    Block* freeList;
    std::mutex mutex;
    
public:
    MemoryPool() : freeList(nullptr) {}
    
    void* allocate(size_t size) {
        std::lock_guard<std::mutex> lock(mutex);
        if (!freeList) {
            // 分配新的内存块
            freeList = static_cast<Block*>(::operator new(size));
            freeList->next = nullptr;
        }
        
        Block* block = freeList;
        freeList = freeList->next;
        return block;
    }
    
    void deallocate(void* ptr, size_t size) {
        std::lock_guard<std::mutex> lock(mutex);
        Block* block = static_cast<Block*>(ptr);
        block->next = freeList;
        freeList = block;
    }
};

4. 性能优化题

4.1 优化字符串处理
// 问题:优化字符串连接操作
// 不推荐
std::string result;
for (int i = 0; i < 1000; ++i) {
    result += "hello";  // 频繁的内存分配
}

// 推荐
std::string result;
result.reserve(5000);  // 预分配内存
for (int i = 0; i < 1000; ++i) {
    result += "hello";
}
4.2 优化内存分配
// 问题:优化频繁的小对象分配
// 不推荐
std::vector<SmallObject> objects;
for (int i = 0; i < 1000; ++i) {
    objects.push_back(SmallObject());  // 频繁的内存分配
}

// 推荐
std::vector<SmallObject> objects;
objects.reserve(1000);  // 预分配内存
for (int i = 0; i < 1000; ++i) {
    objects.emplace_back();  // 原地构造
}

5. 实际项目题

5.1 实现日志系统
// 问题:实现一个线程安全的日志系统
class Logger {
    std::ofstream logFile;
    std::mutex mutex;
    
public:
    Logger(const std::string& filename) {
        logFile.open(filename, std::ios::app);
    }
    
    template<typename... Args>
    void log(Args&&... args) {
        std::lock_guard<std::mutex> lock(mutex);
        auto now = std::chrono::system_clock::now();
        auto time = std::chrono::system_clock::to_time_t(now);
        logFile << std::ctime(&time) << " ";
        (logFile << ... << std::forward<Args>(args)) << std::endl;
    }
};
5.2 实现配置系统
// 问题:实现一个配置系统
class Config {
    std::unordered_map<std::string, std::string> settings;
    std::mutex mutex;
    
public:
    void set(const std::string& key, const std::string& value) {
        std::lock_guard<std::mutex> lock(mutex);
        settings[key] = value;
    }
    
    std::string get(const std::string& key) const {
        std::lock_guard<std::mutex> lock(mutex);
        auto it = settings.find(key);
        return it != settings.end() ? it->second : "";
    }
    
    bool loadFromFile(const std::string& filename) {
        std::ifstream file(filename);
        if (!file) return false;
        
        std::string line;
        while (std::getline(file, line)) {
            size_t pos = line.find('=');
            if (pos != std::string::npos) {
                std::string key = line.substr(0, pos);
                std::string value = line.substr(pos + 1);
                set(key, value);
            }
        }
        return true;
    }
};

6. 面试技巧

  1. 理解问题:确保完全理解面试官的问题,可以适当提问澄清
  2. 分析思路:先说明解题思路,再开始编码
  3. 代码质量:注意代码的健壮性、可读性和性能
  4. 边界情况:考虑异常情况、内存泄漏、线程安全等
  5. 优化改进:说明可能的优化方向
  6. 知识扩展:展示对C++新特性的了解

7. 常见问题类型

  1. 内存管理:智能指针、内存泄漏、内存池
  2. 多线程:线程安全、死锁、同步原语
  3. 设计模式:单例、工厂、观察者等
  4. 性能优化:内存分配、字符串处理、算法优化
  5. 系统设计:日志系统、配置系统、缓存系统
  6. 语言特性:移动语义、完美转发、模板元编程

记住:面试不仅是考察知识,更是考察解决问题的能力和思维方式。在回答问题时,要展示你的思考过程,说明你的设计决策,并考虑代码的可维护性和可扩展性。

8. C++语法和易错点

8.1 初始化相关
// 问题:以下初始化方式有什么区别?
int a = 10;        // 拷贝初始化
int b(10);         // 直接初始化
int c{10};         // 列表初始化
int d = {10};      // 拷贝列表初始化

// 问题:以下代码有什么问题?
class MyClass {
    int x;         // 未初始化
    std::string s; // 默认初始化
public:
    MyClass() {    // 构造函数中未初始化x
        // x未初始化
    }
};

// 正确做法
class MyClass {
    int x{0};      // 类内初始化
    std::string s;
public:
    MyClass() = default;  // 使用默认构造函数
};
8.2 移动语义和完美转发
// 问题:以下代码有什么问题?
void process(std::string str) {
    // 处理str
}

std::string getString() {
    return "hello";
}

process(getString());  // 发生不必要的拷贝

// 正确做法
void process(std::string&& str) {
    // 处理str
}

// 或者使用完美转发
template<typename T>
void process(T&& str) {
    // 处理str
}
8.3 智能指针使用
// 问题:以下代码有什么问题?
std::shared_ptr<int> p1(new int(10));
std::shared_ptr<int> p2 = p1;
std::shared_ptr<int> p3 = p1;  // 引用计数为3

// 问题:以下代码有什么问题?
void func(std::shared_ptr<int> p) {
    // 使用p
}

func(new int(10));  // 错误:不能隐式转换

// 正确做法
func(std::make_shared<int>(10));
8.4 异常安全
// 问题:以下代码有什么问题?
class Resource {
    int* ptr;
public:
    Resource() : ptr(new int(10)) {}
    ~Resource() { delete ptr; }
    
    void setValue(int value) {
        delete ptr;  // 可能抛出异常
        ptr = new int(value);  // 可能抛出异常
    }
};

// 正确做法
class Resource {
    std::unique_ptr<int> ptr;
public:
    Resource() : ptr(std::make_unique<int>(10)) {}
    
    void setValue(int value) {
        ptr = std::make_unique<int>(value);
    }
};
8.5 多线程安全
// 问题:以下代码有什么问题?
class Counter {
    int count;
public:
    void increment() { ++count; }  // 非线程安全
    int getCount() { return count; }
};

// 正确做法
class Counter {
    std::atomic<int> count{0};
public:
    void increment() { ++count; }
    int getCount() { return count; }
};

9. C++代码规范

9.1 命名规范
// 类名:大驼峰
class MyClass {
    // 成员变量:下划线后缀
    int count_;
    std::string name_;
    
    // 私有成员函数:下划线前缀
    void _privateMethod();
    
public:
    // 公共成员函数:小驼峰
    void publicMethod();
    
    // 常量:全大写
    static const int MAX_COUNT = 100;
};

// 命名空间:小写
namespace my_project {
    // 函数:小驼峰
    void processData();
    
    // 变量:小驼峰
    int totalCount = 0;
}
9.2 代码组织
// 头文件组织
#ifndef MY_PROJECT_MY_CLASS_H
#define MY_PROJECT_MY_CLASS_H

#include <string>
#include <vector>

namespace my_project {

class MyClass {
public:
    // 1. 公共类型定义
    using value_type = int;
    
    // 2. 公共常量
    static constexpr int DEFAULT_SIZE = 10;
    
    // 3. 构造函数和析构函数
    MyClass();
    explicit MyClass(int size);
    ~MyClass() = default;
    
    // 4. 公共成员函数
    void process();
    
    // 5. 运算符重载
    MyClass& operator+=(const MyClass& other);
    
private:
    // 6. 私有成员
    std::vector<int> data_;
};

} // namespace my_project

#endif
9.3 注释规范
/**
 * @brief 类的简要描述
 * @details 类的详细描述
 */
class MyClass {
public:
    /**
     * @brief 函数的简要描述
     * @param param1 参数1的描述
     * @param param2 参数2的描述
     * @return 返回值的描述
     * @throws 可能抛出的异常
     */
    int process(int param1, const std::string& param2);
    
private:
    // 成员变量的说明
    int count_;  ///< 计数器
};
9.4 错误处理
// 1. 使用异常处理错误
class DatabaseError : public std::runtime_error {
public:
    explicit DatabaseError(const std::string& msg)
        : std::runtime_error(msg) {}
};

// 2. 使用错误码
enum class ErrorCode {
    Success,
    FileNotFound,
    PermissionDenied
};

// 3. 使用可选值
std::optional<int> findValue(const std::vector<int>& vec, int target);

// 4. 使用预期值
std::expected<int, std::string> divide(int a, int b);
9.5 性能优化
// 1. 使用移动语义
class Resource {
    std::vector<int> data;
public:
    Resource(Resource&& other) noexcept
        : data(std::move(other.data)) {}
};

// 2. 使用引用避免拷贝
void process(const std::string& str);

// 3. 使用emplace_back
std::vector<MyClass> vec;
vec.emplace_back(10, "hello");

// 4. 使用reserve预分配内存
std::vector<int> vec;
vec.reserve(1000);

10. 常见陷阱

10.1 对象生命周期
// 问题:以下代码有什么问题?
class MyClass {
    std::string& str;  // 引用成员
public:
    MyClass(std::string& s) : str(s) {}
};

void func() {
    std::string s = "hello";
    MyClass obj(s);  // 引用可能悬空
}  // s被销毁,obj.str成为悬空引用

// 正确做法
class MyClass {
    std::string str;  // 值成员
public:
    MyClass(const std::string& s) : str(s) {}
};
10.2 迭代器失效
// 问题:以下代码有什么问题?
std::vector<int> vec = {1, 2, 3, 4, 5};
for (auto it = vec.begin(); it != vec.end(); ++it) {
    if (*it == 3) {
        vec.erase(it);  // 迭代器失效
    }
}

// 正确做法
std::vector<int> vec = {1, 2, 3, 4, 5};
vec.erase(
    std::remove_if(vec.begin(), vec.end(),
        [](int x) { return x == 3; }),
    vec.end()
);
10.3 多线程同步
// 问题:以下代码有什么问题?
class Counter {
    int count;
    std::mutex mtx;
public:
    void increment() {
        std::lock_guard<std::mutex> lock(mtx);
        ++count;
    }
    
    int getCount() {
        return count;  // 未加锁
    }
};

// 正确做法
class Counter {
    std::atomic<int> count{0};
public:
    void increment() {
        ++count;
    }
    
    int getCount() {
        return count;
    }
};
10.4 资源管理
// 问题:以下代码有什么问题?
void processFile() {
    FILE* file = fopen("data.txt", "r");
    // 处理文件
    // 可能提前返回或抛出异常
    fclose(file);
}

// 正确做法
void processFile() {
    std::ifstream file("data.txt");
    // 处理文件
    // 自动关闭文件
}

记住:在C++编程中,要注意:

  1. 正确使用初始化语法
  2. 理解移动语义和完美转发
  3. 合理使用智能指针
  4. 确保异常安全
  5. 保证线程安全
  6. 遵循代码规范
  7. 避免常见陷阱
  8. 注意资源管理
  9. 重视性能优化
  10. 保持代码可维护性

11. 智能指针详解

11.1 智能指针类型
  1. unique_ptr
// 独占所有权的智能指针,不能复制,只能移动
std::unique_ptr<int> p1 = std::make_unique<int>(10);
// std::unique_ptr<int> p2 = p1;  // 错误:不能复制
std::unique_ptr<int> p2 = std::move(p1);  // 正确:可以移动

// 自定义删除器
auto deleter = [](int* p) {
    std::cout << "Deleting " << *p << std::endl;
    delete p;
};
std::unique_ptr<int, decltype(deleter)> p3(new int(20), deleter);

// 数组版本
std::unique_ptr<int[]> arr = std::make_unique<int[]>(10);
  1. shared_ptr
// 共享所有权的智能指针,使用引用计数
std::shared_ptr<int> p1 = std::make_shared<int>(10);
std::shared_ptr<int> p2 = p1;  // 引用计数+1
std::shared_ptr<int> p3 = p1;  // 引用计数+1
// p1, p2, p3都指向同一个对象,引用计数为3

// 自定义删除器
std::shared_ptr<FILE> file(
    fopen("data.txt", "r"),
    [](FILE* f) { fclose(f); }
);

// 循环引用问题
class Node {
public:
    std::shared_ptr<Node> next;
    // 可能导致循环引用
};

// 解决循环引用:使用weak_ptr
class Node {
public:
    std::weak_ptr<Node> next;  // 不会增加引用计数
};
  1. weak_ptr
// 弱引用,不增加引用计数
std::shared_ptr<int> sp = std::make_shared<int>(10);
std::weak_ptr<int> wp = sp;  // 不会增加引用计数

// 检查对象是否还存在
if (auto sp2 = wp.lock()) {  // 尝试获取shared_ptr
    // 对象还存在,可以使用sp2
} else {
    // 对象已经被销毁
}

// 用于解决循环引用
class Parent;
class Child {
    std::weak_ptr<Parent> parent;  // 不会导致循环引用
};
  1. auto_ptr (已废弃)
// C++98引入,C++11废弃,C++17移除
// 不要使用auto_ptr,使用unique_ptr代替
std::auto_ptr<int> p1(new int(10));  // 不推荐
std::unique_ptr<int> p2(new int(10));  // 推荐
11.2 智能指针最佳实践
  1. 优先使用make函数
// 不推荐
std::shared_ptr<int> p1(new int(10));
std::unique_ptr<int> p2(new int(10));

// 推荐
auto p1 = std::make_shared<int>(10);
auto p2 = std::make_unique<int>(10);

// 原因:
// 1. 异常安全
// 2. 性能更好(shared_ptr只需要一次内存分配)
// 3. 代码更简洁
  1. 避免循环引用
// 错误示例:循环引用
class Parent {
    std::shared_ptr<Child> child;
};
class Child {
    std::shared_ptr<Parent> parent;
};

// 正确示例:使用weak_ptr
class Parent {
    std::shared_ptr<Child> child;
};
class Child {
    std::weak_ptr<Parent> parent;
};
  1. 合理选择智能指针类型
// 独占所有权:使用unique_ptr
class Resource {
    std::unique_ptr<Data> data;
public:
    Resource() : data(std::make_unique<Data>()) {}
};

// 共享所有权:使用shared_ptr
class Cache {
    std::shared_ptr<Data> data;
public:
    void setData(std::shared_ptr<Data> newData) {
        data = newData;
    }
};

// 观察者模式:使用weak_ptr
class Observer {
    std::weak_ptr<Subject> subject;
public:
    void observe(std::shared_ptr<Subject> s) {
        subject = s;
    }
};
  1. 避免原始指针和智能指针混用
// 不推荐
void process(int* ptr) {
    std::shared_ptr<int> sp(ptr);  // 危险:可能导致重复删除
}

// 推荐
void process(std::shared_ptr<int> sp) {
    // 使用智能指针
}
  1. 自定义删除器
// 文件句柄
auto fileDeleter = [](FILE* f) {
    if (f) fclose(f);
};
std::unique_ptr<FILE, decltype(fileDeleter)> file(
    fopen("data.txt", "r"),
    fileDeleter
);

// 内存池
class MemoryPool {
public:
    void* allocate(size_t size);
    void deallocate(void* ptr);
};

auto poolDeleter = [](void* ptr) {
    MemoryPool::instance().deallocate(ptr);
};
std::unique_ptr<int, decltype(poolDeleter)> data(
    static_cast<int*>(MemoryPool::instance().allocate(sizeof(int))),
    poolDeleter
);
  1. 智能指针和容器
// 使用智能指针作为容器元素
std::vector<std::unique_ptr<Shape>> shapes;
shapes.push_back(std::make_unique<Circle>());
shapes.push_back(std::make_unique<Square>());

// 使用智能指针管理容器
class Container {
    std::unique_ptr<std::vector<int>> data;
public:
    Container() : data(std::make_unique<std::vector<int>>()) {}
};
  1. 智能指针和异常安全
// 不推荐
void process() {
    int* ptr = new int(10);
    // 如果这里抛出异常,会导致内存泄漏
    delete ptr;
}

// 推荐
void process() {
    auto ptr = std::make_unique<int>(10);
    // 即使抛出异常,ptr也会自动释放
}
  1. 智能指针和多线程
// shared_ptr是线程安全的
std::shared_ptr<int> sp = std::make_shared<int>(10);

// 多线程安全地修改shared_ptr
std::mutex mtx;
{
    std::lock_guard<std::mutex> lock(mtx);
    sp = std::make_shared<int>(20);
}

// 使用atomic<shared_ptr>
std::atomic<std::shared_ptr<int>> asp;
asp.store(std::make_shared<int>(10));

记住:

  1. 优先使用make函数创建智能指针
  2. 根据所有权语义选择合适的智能指针类型
  3. 使用weak_ptr避免循环引用
  4. 避免原始指针和智能指针混用
  5. 合理使用自定义删除器
  6. 注意智能指针在多线程环境下的使用
  7. 利用智能指针实现异常安全
  8. 理解智能指针的性能开销

12. 面向对象编程详解

12.1 类的基本概念
  1. 类定义对比
// Java
public class MyClass {
    private int x;
    private String name;
    
    public MyClass(int x, String name) {
        this.x = x;
        this.name = name;
    }
    
    public void setX(int x) {
        this.x = x;
    }
}

// C++
class MyClass {
private:
    int x;
    std::string name;
    
public:
    // 构造函数
    MyClass(int x, const std::string& name) 
        : x(x), name(name) {}  // 初始化列表
    
    // 成员函数
    void setX(int x) {
        this->x = x;  // 使用->而不是.
    }
};
  1. 访问修饰符
// Java: public, protected, private, default(package-private)
// C++: public, protected, private

class MyClass {
public:     // 公有成员,任何地方都可以访问
    int publicVar;
    void publicFunc() {}
    
protected:  // 保护成员,只有本类和子类可以访问
    int protectedVar;
    void protectedFunc() {}
    
private:    // 私有成员,只有本类可以访问
    int privateVar;
    void privateFunc() {}
};
12.2 构造函数和析构函数
  1. 构造函数
class MyClass {
private:
    int x;
    std::string name;
    
public:
    // 默认构造函数
    MyClass() : x(0), name("") {}
    
    // 带参数的构造函数
    MyClass(int x, const std::string& name) 
        : x(x), name(name) {}
    
    // 拷贝构造函数
    MyClass(const MyClass& other) 
        : x(other.x), name(other.name) {}
    
    // 移动构造函数
    MyClass(MyClass&& other) noexcept 
        : x(other.x), name(std::move(other.name)) {}
    
    // 委托构造函数
    MyClass(int x) : MyClass(x, "default") {}
};

// 使用示例
MyClass obj1;              // 默认构造
MyClass obj2(10, "test");  // 带参数构造
MyClass obj3(obj2);        // 拷贝构造
MyClass obj4(std::move(obj3));  // 移动构造
  1. 析构函数
class Resource {
private:
    int* data;
    
public:
    Resource() : data(new int(0)) {}
    
    // 虚析构函数(当类可能被继承时)
    virtual ~Resource() {
        delete data;
    }
};

// 使用示例
{
    Resource res;  // 构造
}  // 析构
12.3 继承和多态
  1. 继承
// 基类
class Base {
protected:
    int x;
    
public:
    Base(int x) : x(x) {}
    virtual void foo() { std::cout << "Base::foo" << std::endl; }
    virtual ~Base() = default;
};

// 公有继承
class Derived : public Base {
private:
    int y;
    
public:
    Derived(int x, int y) : Base(x), y(y) {}
    void foo() override { std::cout << "Derived::foo" << std::endl; }
};

// 保护继承
class ProtectedDerived : protected Base {
    // 基类的public和protected成员变为protected
};

// 私有继承
class PrivateDerived : private Base {
    // 基类的所有成员变为private
};
  1. 多态
// 虚函数
class Shape {
public:
    virtual double area() const = 0;  // 纯虚函数
    virtual ~Shape() = default;
};

class Circle : public Shape {
private:
    double radius;
    
public:
    Circle(double r) : radius(r) {}
    double area() const override {
        return 3.14159 * radius * radius;
    }
};

// 使用示例
std::vector<std::unique_ptr<Shape>> shapes;
shapes.push_back(std::make_unique<Circle>(5));
for (const auto& shape : shapes) {
    std::cout << shape->area() << std::endl;
}
  1. 多重继承
// 基类
class Animal {
public:
    virtual void eat() = 0;
};

class Flying {
public:
    virtual void fly() = 0;
};

// 多重继承
class Bird : public Animal, public Flying {
public:
    void eat() override { std::cout << "Bird eating" << std::endl; }
    void fly() override { std::cout << "Bird flying" << std::endl; }
};

// 虚继承(解决菱形继承问题)
class Base {
public:
    int value;
};

class Derived1 : virtual public Base {};
class Derived2 : virtual public Base {};

class Final : public Derived1, public Derived2 {
    // 只有一个value成员
};
12.4 特殊成员函数
  1. 拷贝控制
class MyClass {
private:
    std::string data;
    
public:
    // 拷贝构造函数
    MyClass(const MyClass& other) : data(other.data) {}
    
    // 拷贝赋值运算符
    MyClass& operator=(const MyClass& other) {
        if (this != &other) {
            data = other.data;
        }
        return *this;
    }
    
    // 移动构造函数
    MyClass(MyClass&& other) noexcept 
        : data(std::move(other.data)) {}
    
    // 移动赋值运算符
    MyClass& operator=(MyClass&& other) noexcept {
        if (this != &other) {
            data = std::move(other.data);
        }
        return *this;
    }
};
  1. 运算符重载
class Complex {
private:
    double real, imag;
    
public:
    Complex(double r, double i) : real(r), imag(i) {}
    
    // 运算符重载
    Complex operator+(const Complex& other) const {
        return Complex(real + other.real, imag + other.imag);
    }
    
    Complex& operator+=(const Complex& other) {
        real += other.real;
        imag += other.imag;
        return *this;
    }
    
    // 友元函数
    friend std::ostream& operator<<(std::ostream& os, const Complex& c) {
        os << c.real << " + " << c.imag << "i";
        return os;
    }
};
12.5 友元
  1. 友元函数
class MyClass {
private:
    int secret;
    
    // 声明友元函数
    friend void friendFunction(MyClass& obj);
    
public:
    MyClass(int s) : secret(s) {}
};

// 友元函数实现
void friendFunction(MyClass& obj) {
    obj.secret = 42;  // 可以直接访问私有成员
}
  1. 友元类
class MyClass {
private:
    int secret;
    
    // 声明友元类
    friend class FriendClass;
    
public:
    MyClass(int s) : secret(s) {}
};

class FriendClass {
public:
    void accessSecret(MyClass& obj) {
        obj.secret = 100;  // 可以直接访问私有成员
    }
};
12.6 Java和C++面向对象的主要区别
  1. 内存管理

    • Java:自动垃圾回收
    • C++:手动内存管理或智能指针
  2. 多重继承

    • Java:只支持接口的多重继承
    • C++:支持类的多重继承
  3. 虚函数

    • Java:所有方法默认都是虚函数
    • C++:需要显式声明virtual
  4. 访问控制

    • Java:public, protected, private, default
    • C++:public, protected, private
  5. 构造函数

    • Java:只能通过this()调用其他构造函数
    • C++:支持初始化列表和委托构造函数
  6. 析构函数

    • Java:没有析构函数,使用finalize()
    • C++:有析构函数,支持RAII
  7. 运算符重载

    • Java:不支持运算符重载
    • C++:支持运算符重载
  8. 友元

    • Java:没有友元概念
    • C++:支持友元函数和友元类
  9. 默认函数

    • Java:自动生成默认构造函数
    • C++:可以控制是否生成默认函数
  10. 接口

    • Java:使用interface关键字
    • C++:使用纯虚类实现接口

记住:

  1. C++的面向对象特性比Java更灵活但更复杂
  2. 理解C++的内存管理机制
  3. 合理使用虚函数和继承
  4. 注意多重继承的复杂性
  5. 掌握运算符重载的使用
  6. 理解友元机制的作用
  7. 重视RAII原则
  8. 注意拷贝控制和移动语义

// ... existing code ...