C++ 中函数参数传递(值传递、指针传递、引用传递和const 引用传递)等内容详解

C++ 中函数参数传递是一个非常核心但也容易忽视的知识点,合理使用可以显著提高程序的性能和安全性。下面我会给出详尽的讲解、注意事项和丰富的示例。


C++ 参数传递方式详解

方式 语法 是否复制 可修改原对象 典型用途
值传递 void foo(Type x) ✅ 是 ❌ 否 小型对象、基本类型
指针传递 void foo(Type* x) ❌ 否 ✅ 是(非 const) 允许修改;可空
引用传递 void foo(Type& x) ❌ 否 ✅ 是(非 const) 修改原对象,传大型对象
const 引用传递 void foo(const Type& x) ❌ 否 ❌ 否 高效读取大型对象
右值引用传递 void foo(Type&& x) ❌ 否 ✅ 是 接受临时对象、支持移动语义

各种方式适用场景和注意事项

1. 值传递(by value)

void increment(int x) {
    x += 1;  // 修改的是副本
}
  • 安全,函数内部修改不会影响调用者
  • 对大型对象(如 std::string、std::vector)会有复制开销

2. 指针传递(by pointer)

void setZero(int* ptr) {
    if (ptr) *ptr = 0;
}
  • ✅ 可修改原始变量
  • ❗ 需要检查指针非空,易出错

3. 引用传递(by reference)

void swap(int& a, int& b) {
    int tmp = a; a = b; b = tmp;
}
  • 高效(不复制),代码清晰
  • 不可传 null,不可看到是否被修改

4. 常量引用传递(by const reference)

void printString(const std::string& s) {
    std::cout << s << "\n";
}
  • 推荐用于大型对象的只读传参
  • 不可修改,但比值传递高效

5. 右值引用传递(by rvalue reference) — C++11+

void takeOwnership(std::string&& s) {
    std::cout << "Moved: " << s << "\n";
}
  • 实现移动语义,避免拷贝(std::move
  • 接收临时变量/转移资源所有权

示例:函数参数传递效果对比

#include 
#include 

void byValue(std::string s) {
    s += " world";  // 改的是副本
}
void byPointer(std::string* s) {
    if (s) *s += " world";
}
void byReference(std::string& s) {
    s += " world";
}
void byConstRef(const std::string& s) {
    std::cout << "Only viewing: " << s << "\n";
}
void byRValue(std::string&& s) {
    std::cout << "Moved: " << s << "\n";
}

int main() {
    std::string str = "hello";

    byValue(str);
    std::cout << "After byValue: " << str << "\n";  // 不变

    byPointer(&str);
    std::cout << "After byPointer: " << str << "\n";  // 变化

    byReference(str);
    std::cout << "After byReference: " << str << "\n";  // 变化

    byConstRef(str);  // 只读

    byRValue(std::move(str));  // 移动语义,str 可能被清空
    std::cout << "After move: " << str << "\n";  // 可能为空

    return 0;
}

总结:使用建议

用途 推荐方式
小型类型(int, double) 值传递
只读大型对象(std::vector 等) const 引用传递
可修改对象 引用或指针传递(引用更安全)
条件修改或可能为 null 指针传递
移动资源所有权 右值引用(+ std::move

综合例子

下面通过模拟一个 “字符串处理器”系统,通过交互演示:

  • 值传递:函数收到的是副本,外部不变
  • 指针传递:修改原数据,需要检查 null
  • 引用传递:高效修改原数据
  • 常量引用:只读但不复制大型对象
  • 右值引用:移动语义,偷资源

string_processor.h的内容:

#pragma once
#include 

class StringProcessor {
public:
    // 值传递
    static void toUpperCopy(std::string str);

    // 指针传递
    static void toUpperPtr(std::string* str);

    // 引用传递
    static void toUpperRef(std::string& str);

    // 常量引用传递
    static void printLength(const std::string& str);

    // 右值引用传递
    static void takeOwnership(std::string&& str);
};

string_processor.cpp的内容:

#include "string_processor.h"
#include 
#include 

void StringProcessor::toUpperCopy(std::string str) {
    for (char& c : str) c = std::toupper(c);
    std::cout << "[toUpperCopy] result (local only): " << str << "\n";
}

void StringProcessor::toUpperPtr(std::string* str) {
    if (str) {
        for (char& c : *str) c = std::toupper(c);
    }
}

void StringProcessor::toUpperRef(std::string& str) {
    for (char& c : str) c = std::toupper(c);
}

void StringProcessor::printLength(const std::string& str) {
    std::cout << "[printLength] Length: " << str.length() << "\n";
}

void StringProcessor::takeOwnership(std::string&& str) {
    std::cout << "[takeOwnership] Moved string: " << str << "\n";
}

main.cpp主函数使用的内容:

#include "string_processor.h"
#include 
#include 

void menu() {
    std::cout << "\n==== 字符串处理器 - 类型传递演示 ====\n";
    std::cout << "1. 值传递 (toUpperCopy)\n";
    std::cout << "2. 指针传递 (toUpperPtr)\n";
    std::cout << "3. 引用传递 (toUpperRef)\n";
    std::cout << "4. 常量引用 (printLength)\n";
    std::cout << "5. 右值引用 (takeOwnership)\n";
    std::cout << "0. 退出\n";
    std::cout << "请选择操作编号: ";
}

int main() {
    std::string str;
    std::cout << "请输入初始字符串:";
    std::getline(std::cin, str);

    int choice;
    do {
        menu();
        std::cin >> choice;
        std::cin.ignore();  // 清除换行

        switch (choice) {
            case 1:
                StringProcessor::toUpperCopy(str);
                std::cout << "原始字符串仍是: " << str << "\n";
                break;
            case 2:
                StringProcessor::toUpperPtr(&str);
                std::cout << "修改后字符串: " << str << "\n";
                break;
            case 3:
                StringProcessor::toUpperRef(str);
                std::cout << "修改后字符串: " << str << "\n";
                break;
            case 4:
                StringProcessor::printLength(str);
                break;
            case 5:
                StringProcessor::takeOwnership(std::move(str));
                std::cout << "原始字符串现在是: " << str << "\n";
                break;
            case 0:
                std::cout << "程序结束。\n";
                break;
            default:
                std::cout << "无效选择,请重试。\n";
        }
    } while (choice != 0);

    return 0;
}

示例小结说明

菜单选项 类型传递 说明
1 值传递 toUpperCopy:不修改原始字符串
2 指针传递 toUpperPtr:通过指针修改
3 引用传递 toUpperRef:直接修改字符串内容
4 常量引用 printLength:只读且高效
5 右值引用 takeOwnership:偷走数据、原字符串置空

你可能感兴趣的:(C++,c++,开发语言,C++,参数传递,指针传递,引用传递,C++函数参数)