最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++中的引用傳參和指針傳參的區(qū)別小結(jié)

 更新時(shí)間:2026年02月19日 10:11:47   作者:sTone87375  
本文主要介紹了C++中的引用傳參和指針傳參的區(qū)別小結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

核心概念對(duì)比

概念C++前端 (JS/TS)
值傳遞默認(rèn)方式,完整拷貝基本類型 (number, string等)
引用傳遞需顯式使用 & 或指針對(duì)象、數(shù)組、函數(shù)等引用類型
指針傳遞傳遞內(nèi)存地址類似傳遞對(duì)象的引用

1. 值傳遞(默認(rèn))- 完整拷貝

#include <iostream>
using namespace std;

struct Point {
    int x, y;
    Point(int a, int b) : x(a), y(b) {
        cout << "構(gòu)造: (" << x << "," << y << ")" << endl;
    }
    Point(const Point& p) : x(p.x), y(p.y) {
        cout << "拷貝構(gòu)造: (" << x << "," << y << ")" << endl;
    }
    ~Point() {
        cout << "析構(gòu): (" << x << "," << y << ")" << endl;
    }
};

// ? 值傳遞:發(fā)生完整拷貝
void byValue(Point p) {
    p.x = 100;  // 修改的是副本,不影響原對(duì)象
    cout << "函數(shù)內(nèi): (" << p.x << "," << p.y << ")" << endl;
}

int main() {
    Point p1(1, 2);
    cout << "--- 調(diào)用函數(shù) ---" << endl;
    byValue(p1);
    cout << "--- 函數(shù)返回 ---" << endl;
    cout << "原對(duì)象: (" << p1.x << "," << p1.y << ")" << endl;  // 仍是 (1,2)
    return 0;
}

輸出:

構(gòu)造: (1,2)
--- 調(diào)用函數(shù) ---
拷貝構(gòu)造: (1,2)
函數(shù)內(nèi): (100,2)
析構(gòu): (100,2)
--- 函數(shù)返回 ---
原對(duì)象: (1,2)
析構(gòu): (1,2)

?? 性能問題:大對(duì)象會(huì)發(fā)生昂貴的深拷貝

2. 引用傳遞(類似前端引用類型)

// ? 引用傳遞:不拷貝,直接操作原對(duì)象(類似前端的對(duì)象引用)
void byReference(Point& p) {
    p.x = 100;  // 直接修改原對(duì)象!
    cout << "函數(shù)內(nèi): (" << p.x << "," << p.y << ")" << endl;
}

// ? const 引用:只讀訪問,不拷貝也不能修改
void byConstReference(const Point& p) {
    // p.x = 100;  // ? 編譯錯(cuò)誤:不能修改const引用
    cout << "只讀訪問: (" << p.x << "," << p.y << ")" << endl;
}

int main() {
    Point p1(1, 2);
    
    cout << "=== 引用傳遞 ===" << endl;
    byReference(p1);
    cout << "原對(duì)象已被修改: (" << p1.x << "," << p1.y << ")" << endl;  // (100,2)
    
    cout << "\n=== const引用 ===" << endl;
    byConstReference(p1);
    
    return 0;
}

與前端對(duì)比:

// JavaScript - 對(duì)象天然是引用傳遞
function modify(obj) {
    obj.x = 100;  // 直接修改原對(duì)象
}
let p = {x: 1, y: 2};
modify(p);
console.log(p.x);  // 100 ?

// C++ 必須顯式加 & 才能實(shí)現(xiàn)同樣效果

3. 指針傳遞(C風(fēng)格,更靈活但危險(xiǎn))

// 指針傳遞:傳遞內(nèi)存地址
void byPointer(Point* p) {
    if (p != nullptr) {  // 必須檢查空指針!
        p->x = 200;      // 使用 -> 訪問成員
    }
}

// 指針的const版本
void byConstPointer(const Point* p) {
    // p->x = 200;  // ? 不能修改
    cout << p->x << endl;  // ? 可以讀取
}

int main() {
    Point p1(1, 2);
    
    byPointer(&p1);  // 必須取地址
    cout << "修改后: (" << p1.x << "," << p1.y << ")" << endl;
    
    // 可以傳 nullptr(這是與引用的重要區(qū)別)
    byPointer(nullptr);  // ? 合法
    
    return 0;
}

引用 vs 指針對(duì)比:

特性引用 &指針 *
語(yǔ)法更簡(jiǎn)潔,像原對(duì)象需解引用 -> 或 *
空值不能為 null可以為 nullptr
重新綁定不能改指向其他對(duì)象可以指向不同對(duì)象
安全性更高(必須初始化)需檢查空指針

4. 返回值優(yōu)化(RVO)與移動(dòng)語(yǔ)義

傳統(tǒng)返回值(有拷貝)

// ? C++11前:返回時(shí)會(huì)發(fā)生拷貝(或編譯器RVO優(yōu)化)
Point createPoint() {
    Point p(3, 4);
    return p;  // 理論上會(huì)拷貝,但編譯器通常優(yōu)化掉
}

// 接收時(shí)再次拷貝
Point p2 = createPoint();

現(xiàn)代C++:移動(dòng)語(yǔ)義(C++11起)

struct BigData {
    int* data;
    size_t size;
    
    // 移動(dòng)構(gòu)造函數(shù)(轉(zhuǎn)移資源所有權(quán),不拷貝數(shù)據(jù))
    BigData(BigData&& other) noexcept 
        : data(other.data), size(other.size) {
        cout << "移動(dòng)構(gòu)造(偷資源)" << endl;
        other.data = nullptr;  // 置空源對(duì)象
        other.size = 0;
    }
    
    // 移動(dòng)賦值
    BigData& operator=(BigData&& other) noexcept {
        cout << "移動(dòng)賦值" << endl;
        if (this != &other) {
            delete[] data;
            data = other.data;
            size = other.size;
            other.data = nullptr;
        }
        return *this;
    }
};

BigData createBigData() {
    BigData bd(1000000);  // 分配大量?jī)?nèi)存
    return bd;  // 觸發(fā)移動(dòng)語(yǔ)義,而非深拷貝!
}

int main() {
    BigData bd1 = createBigData();  // 移動(dòng)構(gòu)造,幾乎零開銷
    BigData bd2;
    bd2 = createBigData();          // 移動(dòng)賦值
    return 0;
}

5. 最佳實(shí)踐總結(jié)

// ? 最佳實(shí)踐速查表

// 1. 小對(duì)象(int, double, 小結(jié)構(gòu)體):直接值傳遞
void f(int x, Point p);  

// 2. 大對(duì)象只讀訪問:const 引用(性能+安全)
void process(const BigData& data);

// 3. 需要修改原對(duì)象:非const引用
void modify(Point& p);

// 4. 參數(shù)可選(可能為空):指針
void maybeProcess(BigData* data);  // data可以是nullptr

// 5. 轉(zhuǎn)移所有權(quán)(C++11):右值引用
void takeOwnership(BigData&& data);

// 6. 返回值:優(yōu)先返回值(依賴RVO/移動(dòng)),而非輸出參數(shù)
BigData create();  // ? 現(xiàn)代C++推薦
void create(BigData& out);  // 舊式風(fēng)格,避免

類比總結(jié)

// C++ 顯式控制傳遞方式
void f(Point p);      // 值傳遞(拷貝)    ← 像 JS 的 structuredClone
void f(Point& p);     // 引用傳遞(別名)   ← 像 JS 的對(duì)象引用
void f(const Point& p); // const引用       ← 像 JS 的只讀引用
void f(Point* p);     // 指針傳遞         ← 像 JS 的弱引用/可空引用
void f(Point&& p);    // 右值引用(移動(dòng))   ← 像 JS 的 對(duì)象轉(zhuǎn)移/解構(gòu)賦值

關(guān)鍵區(qū)別:C++ 默認(rèn)是值語(yǔ)義(拷貝),必須顯式使用 & 才能獲得引用語(yǔ)義;而前端(JS)對(duì)象默認(rèn)就是引用語(yǔ)義。

以下深入剖析 C++ 中引用傳遞和指針傳遞的本質(zhì)差異。

核心對(duì)比表

維度引用傳遞 T&指針傳遞 T*
本質(zhì)別名(alias),必須綁定有效對(duì)象內(nèi)存地址,可獨(dú)立存在
空值? 不能為 null? 可以為 nullptr
重新綁定? 終身綁定,不能改指向? 可隨時(shí)指向其他對(duì)象
語(yǔ)法使用原對(duì)象語(yǔ)法 .需解引用 -> 或 *
初始化必須初始化可以延遲初始化
內(nèi)存占用通常優(yōu)化為無(wú)開銷占用指針大小(4/8字節(jié))

本質(zhì)差異圖解

引用 (&)                    指針 (*)
┌─────────┐                ┌─────────┐
│  引用變量  │ ──→ 對(duì)象      │ 指針變量  │ ──→ 對(duì)象
│  (別名)   │   (必須存在)   │ (地址)   │   或 ──→ nullptr
└─────────┘                └─────────┘
   語(yǔ)法糖,編譯器處理           真正的內(nèi)存實(shí)體

代碼層面深度對(duì)比

1. 基礎(chǔ)語(yǔ)法差異

#include <iostream>
using namespace std;

struct Config {
    int port;
    string host;
};

// ========== 引用版本 ==========
void setupByRef(Config& cfg) {
    // 語(yǔ)法:直接使用對(duì)象
    cfg.port = 8080;
    cfg.host = "localhost";
    
    // ? 不能檢查是否為空(假設(shè)一定存在)
    // if (&cfg == nullptr) {}  // 無(wú)意義,引用不能為null
}

// ========== 指針版本 ==========
void setupByPtr(Config* cfg) {
    // 語(yǔ)法:必須先檢查空指針
    if (cfg == nullptr) {
        cerr << "錯(cuò)誤:配置為空" << endl;
        return;
    }
    
    // 解引用方式1:->
    cfg->port = 8080;
    
    // 解引用方式2:*(獲取引用后再用.)
    (*cfg).host = "localhost";
}

int main() {
    Config c{0, ""};
    
    // 引用調(diào)用:簡(jiǎn)單直接
    setupByRef(c);
    
    // 指針調(diào)用:必須取地址
    setupByPtr(&c);
    setupByPtr(nullptr);  // ? 可以傳空,函數(shù)內(nèi)部處理
    
    return 0;
}

2. 重新綁定能力(關(guān)鍵差異)

void demonstrateRebinding() {
    int a = 10, b = 20;
    
    // ========== 引用:終身綁定 ==========
    int& ref = a;
    ref = b;      // ? 這不是讓ref指向b!而是把b的值賦給a
                  // 結(jié)果:a = 20, ref仍是a的別名
    
    // 想改指向?不可能!
    // &ref = b;   // 編譯錯(cuò)誤!
    
    // ========== 指針:靈活重定向 ==========
    int* ptr = &a;
    cout << *ptr;  // 10
    
    ptr = &b;      // ? 隨時(shí)改指向
    cout << *ptr;  // 20
    
    ptr = nullptr; // ? 可以指向空
}

3. 多級(jí)間接訪問

// 指針可以指向指針,引用不行
void pointerChain() {
    int x = 42;
    int* p = &x;
    int** pp = &p;      // ? 指針的指針
    int*** ppp = &pp;   // ? 可以無(wú)限套娃
    
    cout << ***ppp;     // 42
    
    // 引用只有一級(jí)(引用的引用被折疊)
    int& r = x;
    // int&& rr = r;    // 這是右值引用,不是引用的引用!
}

本質(zhì)差異:編譯器視角

// 源代碼
void byRef(int& r) { r = 10; }
void byPtr(int* p) { *p = 10; }

int main() {
    int x = 5;
    byRef(x);
    byPtr(&x);
}

編譯后的偽代碼:

; 引用版本(編譯器優(yōu)化后,與指針相同)
byRef:
    mov eax, [esp+4]    ; 取地址(與指針一樣!)
    mov dword [eax], 10 ; 解引用賦值
    
; 指針版本
byPtr:
    mov eax, [esp+4]    ; 取地址
    test eax, eax       ; ? 檢查空指針(編譯器可能優(yōu)化掉)
    je .null_handler
    mov dword [eax], 10
    
; 結(jié)論:引用是指針的語(yǔ)法糖,但編譯器保證非空

本質(zhì)真相:引用在底層就是指針,但編譯器添加了非空約束自動(dòng)解引用的語(yǔ)法糖。

適用場(chǎng)景詳解

? 引用傳遞適用場(chǎng)景

// 場(chǎng)景1:參數(shù)必須存在(業(yè)務(wù)邏輯要求)
void connectDatabase(const ConnectionConfig& config) {
    // 配置必須提供,不存在"無(wú)配置"的情況
    // 無(wú)需檢查空,簡(jiǎn)化代碼
}

// 場(chǎng)景2:操作符重載(只能用引用)
class Vector {
public:
    // 必須返回引用才能鏈?zhǔn)劫x值:v1 = v2 = v3
    Vector& operator=(const Vector& other) {
        // ...
        return *this;  // 解引用返回引用
    }
    
    // 下標(biāo)運(yùn)算符
    int& operator[](size_t index) {
        return data[index];  // 必須返回引用才能:v[0] = 10
    }
};

// 場(chǎng)景3:函數(shù)式編程風(fēng)格(明確所有權(quán))
void sort(vector<int>& data);           // 修改原數(shù)據(jù)
void print(const vector<int>& data);    // 只讀訪問

? 指針傳遞適用場(chǎng)景

// 場(chǎng)景1:參數(shù)可選(可為空)
void logMessage(const string* prefix = nullptr) {
    if (prefix) {
        cout << "[" << *prefix << "] ";
    }
    cout << "日志內(nèi)容" << endl;
}
// 調(diào)用:logMessage(); 或 logMessage(&debugTag);

// 場(chǎng)景2:動(dòng)態(tài)內(nèi)存管理(所有權(quán)轉(zhuǎn)移)
void processLargeFile(unique_ptr<FileData>* filePtr) {
    // 可能轉(zhuǎn)移所有權(quán),或釋放內(nèi)存
    if (filePtr && *filePtr) {
        auto data = std::move(*filePtr);  // 接管所有權(quán)
        // filePtr 現(xiàn)在指向空unique_ptr
    }
}

// 場(chǎng)景3:C接口兼容/多態(tài)數(shù)組
void drawShapes(Shape** shapes, size_t count) {
    // 指針數(shù)組,支持運(yùn)行時(shí)多態(tài)
    for (size_t i = 0; i < count; ++i) {
        shapes[i]->draw();  // 虛函數(shù)調(diào)用
    }
}

// 場(chǎng)景4:需要重新指向(迭代、遍歷)
Node* findNode(Node* head, int value) {
    Node* current = head;      // 從head開始
    while (current) {
        if (current->val == value) return current;
        current = current->next;  // ? 指針可以遍歷
    }
    return nullptr;
}
// 如果用引用:Node& current = head; current = ... 會(huì)修改原h(huán)ead!

現(xiàn)代C++的最佳實(shí)踐

// ?? 參數(shù)傳遞決策樹

// 1. 小對(duì)象(<= 2個(gè)指針大小):值傳遞
void f(int x, Point p);

// 2. 只讀大對(duì)象:const 引用(首選)
void process(const BigData& data);

// 3. 必須修改原對(duì)象:非const 引用
void modify(Config& cfg);

// 4. 參數(shù)可選/可為空:指針
void render(const Camera* cam = nullptr);

// 5. 轉(zhuǎn)移所有權(quán)(C++11):右值引用
void consume(vector<int>&& data);

// 6. 動(dòng)態(tài)數(shù)組/多態(tài):智能指針
void loadModel(shared_ptr<Mesh> mesh);      // 共享所有權(quán)
void takeData(unique_ptr<Buffer> buffer);   // 獨(dú)占所有權(quán)

一句話總結(jié)

引用是"承諾存在的別名",指針是"可能為空的地址"。

用引用表達(dá)契約(必須存在),用指針表達(dá)可選性(可能為空)。

到此這篇關(guān)于C++中的引用傳參和指針傳參的區(qū)別小結(jié)的文章就介紹到這了,更多相關(guān)C++ 引用傳參和指針傳參內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

客服| 陕西省| 江门市| 普兰县| 泰来县| 台湾省| 吕梁市| 时尚| 乐东| 方山县| 临桂县| 绥芬河市| 巴中市| 新巴尔虎左旗| 耒阳市| 邳州市| 三台县| 敦煌市| 英山县| 林口县| 唐河县| 南部县| 宁明县| 东兴市| 达孜县| 乐业县| 洞口县| 平阴县| 长丰县| 焦作市| 衡南县| 响水县| 深水埗区| 独山县| 若羌县| 东宁县| 孟村| 杂多县| 信丰县| 海原县| 兴山县|