值传递(Pass by Value)
基本概念
值传递是将实参的值复制给形参,函数内部操作的是副本,不会影响原始变量。
void modifyValue(int x) {
x = 100; // 只修改局部副本
std::cout << "Inside function: " << x << std::endl; // 100
}
int main() {
int a = 10;
modifyValue(a);
std::cout << "After function: " << a << std::endl; // 10,未改变
return 0;
}
对象的值传递
class Person {
public:
std::string name;
int age;
Person(const std::string& n, int a) : name(n), age(a) {
std::cout << "Constructor called for " << name << std::endl;
}
Person(const Person& other) : name(other.name), age(other.age) {
std::cout << "Copy constructor called for " << name << std::endl;
}
~Person() {
std::cout << "Destructor called for " << name << std::endl;
}
};
void processPerson(Person p) { // 值传递,会调用拷贝构造函数
p.age = 100; // 只修改副本
std::cout << "Inside function: " << p.name << " is " << p.age << std::endl;
}
int main() {
Person alice("Alice", 25);
processPerson(alice); // 触发拷贝构造函数
std::cout << "After function: " << alice.name << " is " << alice.age << std::endl;
return 0;
}
// 输出:
// Constructor called for Alice
// Copy constructor called for Alice
// Inside function: Alice is 100
// Destructor called for Alice (副本析构)
// After function: Alice is 25
// Destructor called for Alice (原对象析构)
值传递的优缺点
// 优点:安全,不会意外修改原始数据
int safeCalculation(int value) {
value *= 2; // 不影响原始值
return value;
}
// 缺点:性能开销,特别是大对象
void inefficientFunction(std::vector<int> vec) { // 拷贝整个 vector
// 处理 vec
}
// 改进:使用 const 引用
void efficientFunction(const std::vector<int>& vec) { // 不拷贝
// 处理 vec,但不能修改
}
引用传递(Pass by Reference)
基本引用传递
void modifyReference(int& x) {
x = 100; // 直接修改原始变量
}
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 10, y = 20;
modifyReference(x);
std::cout << "x = " << x << std::endl; // 100
swap(x, y);
std::cout << "x = " << x << ", y = " << y << std::endl; // x = 20, y = 100
return 0;
}
常量引用传递
// 避免拷贝,同时防止修改
void printPerson(const Person& p) {
std::cout << p.name << " is " << p.age << " years old" << std::endl;
// p.age = 30; // 编译错误!不能修改 const 引用
}
// 返回引用以支持链式调用
class Counter {
int count = 0;
public:
Counter& increment() {
++count;
return *this; // 返回自身引用
}
Counter& add(int value) {
count += value;
return *this;
}
int getValue() const { return count; }
};
int main() {
Counter c;
c.increment().add(5).increment(); // 链式调用
std::cout << c.getValue() << std::endl; // 7
}
引用的限制和注意事项
// 引用必须初始化
void function() {
int& ref; // 编译错误!引用必须初始化
}
// 引用不能重新绑定
void rebindReference() {
int a = 10, b = 20;
int& ref = a;
ref = b; // 这是赋值,不是重新绑定!ref 仍然引用 a
std::cout << a << std::endl; // 20,a 的值被改变了
}
// 不能创建引用的数组
void arrayOfReferences() {
int a = 1, b = 2;
// int& refs[] = {a, b}; // 编译错误!
}
// 返回局部变量的引用是危险的
int& dangerousFunction() {
int local = 42;
return local; // 危险!返回局部变量的引用
} // local 在这里被销毁
// 安全的引用返回
class SafeContainer {
std::vector<int> data;
public:
int& at(size_t index) {
return data.at(index); // 返回容器元素的引用
}
const int& at(size_t index) const {
return data.at(index); // const 版本
}
};
指针传递(Pass by Pointer)
基本指针传递
void modifyPointer(int* x) {
if (x != nullptr) {
*x = 100; // 修改指针指向的值
}
}
void allocateMemory(int** ptr) {
*ptr = new int(42); // 修改指针本身
}
int main() {
int a = 10;
modifyPointer(&a);
std::cout << "a = " << a << std::endl; // 100
int* p = nullptr;
allocateMemory(&p);
std::cout << "*p = " << *p << std::endl; // 42
delete p; // 记得释放内存
return 0;
}
指针与数组
// 数组作为参数实际上是指针
void printArray(int arr[], int size) { // 等价于 int* arr
for (int i = 0; i < size; i++) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
}
// 多维数组
void print2DArray(int arr[][3], int rows) { // 第一维可以省略,其他维不能
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 3; j++) {
std::cout << arr[i][j] << " ";
}
std::cout << std::endl;
}
}
// 使用指针的指针
void print2DArrayPtr(int** arr, int rows, int cols) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
std::cout << arr[i][j] << " ";
}
std::cout << std::endl;
}
}
智能指针传递
#include <memory>
// 传递 unique_ptr
void processUniquePtr(std::unique_ptr<int> ptr) { // 转移所有权
std::cout << "Value: " << *ptr << std::endl;
// ptr 在函数结束时自动释放
}
void processUniquePtrRef(const std::unique_ptr<int>& ptr) { // 不转移所有权
if (ptr) {
std::cout << "Value: " << *ptr << std::endl;
}
}
// 传递 shared_ptr
void processSharedPtr(std::shared_ptr<int> ptr) { // 增加引用计数
std::cout << "Value: " << *ptr << std::endl;
std::cout << "Reference count: " << ptr.use_count() << std::endl;
}
int main() {
auto unique_ptr = std::make_unique<int>(42);
processUniquePtrRef(unique_ptr); // 不转移所有权
// processUniquePtr(std::move(unique_ptr)); // 转移所有权
auto shared_ptr = std::make_shared<int>(100);
std::cout << "Before: " << shared_ptr.use_count() << std::endl; // 1
processSharedPtr(shared_ptr); // 临时增加引用计数
std::cout << "After: " << shared_ptr.use_count() << std::endl; // 1
return 0;
}
右值引用和移动语义(C++11)
右值引用基础
// 左值引用 vs 右值引用
void processLValue(int& x) {
std::cout << "LValue: " << x << std::endl;
}
void processRValue(int&& x) {
std::cout << "RValue: " << x << std::endl;
}
// 重载解析
void process(const std::string& s) {
std::cout << "LValue/const: " << s << std::endl;
}
void process(std::string&& s) {
std::cout << "RValue: " << s << std::endl;
}
int main() {
int a = 10;
processLValue(a); // OK,a 是左值
// processLValue(20); // 错误!20 是右值
processRValue(20); // OK,20 是右值
// processRValue(a); // 错误!a 是左值
std::string str = "hello";
process(str); // 调用左值版本
process("world"); // 调用右值版本
process(std::move(str)); // 强制调用右值版本
return 0;
}
移动构造和移动赋值
class MoveableClass {
std::vector<int> data;
std::string name;
public:
// 构造函数
MoveableClass(const std::string& n) : name(n) {
data.resize(1000000); // 大量数据
std::cout << "Constructor: " << name << std::endl;
}
// 拷贝构造函数
MoveableClass(const MoveableClass& other)
: data(other.data), name(other.name) {
std::cout << "Copy constructor: " << name << std::endl;
}
// 移动构造函数
MoveableClass(MoveableClass&& other) noexcept
: data(std::move(other.data)), name(std::move(other.name)) {
std::cout << "Move constructor: " << name << std::endl;
}
// 拷贝赋值运算符
MoveableClass& operator=(const MoveableClass& other) {
if (this != &other) {
data = other.data;
name = other.name;
std::cout << "Copy assignment: " << name << std::endl;
}
return *this;
}
// 移动赋值运算符
MoveableClass& operator=(MoveableClass&& other) noexcept {
if (this != &other) {
data = std::move(other.data);
name = std::move(other.name);
std::cout << "Move assignment: " << name << std::endl;
}
return *this;
}
};
// 函数参数中的移动语义
void processByValue(MoveableClass obj) { // 可能触发移动
// 使用 obj
}
void processByRValueRef(MoveableClass&& obj) { // 接受右值
// 可以移动 obj 的内容
MoveableClass local = std::move(obj);
}
int main() {
MoveableClass obj1("Object1");
// 拷贝
MoveableClass obj2 = obj1; // 拷贝构造
// 移动
MoveableClass obj3 = std::move(obj1); // 移动构造
// 函数调用
processByValue(MoveableClass("Temp")); // 移动构造(临时对象)
processByRValueRef(MoveableClass("Temp2")); // 直接构造
return 0;
}
完美转发(Perfect Forwarding)
#include <utility>
// 转发函数,保持参数的值类别
template<typename T>
void wrapper(T&& arg) {
// std::forward 保持 arg 的值类别
actualFunction(std::forward<T>(arg));
}
// 实际处理函数
void actualFunction(const std::string& s) {
std::cout << "LValue: " << s << std::endl;
}
void actualFunction(std::string&& s) {
std::cout << "RValue: " << s << std::endl;
}
// 可变参数模板的完美转发
template<typename Func, typename... Args>
auto callFunction(Func&& func, Args&&... args)
-> decltype(func(std::forward<Args>(args)...)) {
return func(std::forward<Args>(args)...);
}
// 工厂函数示例
template<typename T, typename... Args>
std::unique_ptr<T> make_unique_custom(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
int main() {
std::string str = "hello";
wrapper(str); // 转发左值
wrapper("world"); // 转发右值
wrapper(std::move(str)); // 转发移动的值
// 使用工厂函数
auto ptr = make_unique_custom<std::string>("Hello World");
return 0;
}
函数对象和可调用对象
函数指针作为参数
// 函数指针类型
typedef int (*BinaryOp)(int, int);
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }
void calculate(int x, int y, BinaryOp op) {
int result = op(x, y);
std::cout << "Result: " << result << std::endl;
}
int main() {
calculate(5