成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

C++如何解決頭文件循環(huán)引用問(wèn)題?至少給出兩種方法

開(kāi)發(fā) 前端
在 A.h 和 B.h 中,我們只前向聲明了各自的實(shí)現(xiàn)類 Impl,而沒(méi)有包含對(duì)方的頭文件。這樣,頭文件之間不再存在直接的依賴關(guān)系,從而避免了循環(huán)引用。

頭文件循環(huán)引用是C++編程中常見(jiàn)的問(wèn)題,通常發(fā)生在兩個(gè)或多個(gè)頭文件相互包含對(duì)方的情況下。這種情況下,編譯器可能會(huì)陷入無(wú)限遞歸,導(dǎo)致編譯錯(cuò)誤或不正確的代碼生成。 

1、問(wèn)題描述

首先看一個(gè)典型的循環(huán)引用場(chǎng)景: 

// a.h
#ifndef A_H
#define A_H
#include "b.h"

class A {
    B* b_ptr;  // 需要完整的B類定義
public:
    void doSomething();
};
#endif

// b.h
#ifndef B_H
#define B_H
#include "a.h"

class B {
    A* a_ptr;  // 需要完整的A類定義
public:
    void doSomething();
};
#endif

這會(huì)導(dǎo)致編譯錯(cuò)誤,因?yàn)閮蓚€(gè)頭文件互相包含。 

2、解決方案

2.1 前向聲明

最常用也是最簡(jiǎn)單的方法: 

// a.h
#ifndef A_H
#define A_H

class B;  // 前向聲明

class A {
    B* b_ptr;  // 只需要不完整類型聲明
public:
    void doSomething();
};
#endif

// b.h
#ifndef B_H
#define B_H

class A;  // 前向聲明

class B {
    A* a_ptr;  // 只需要不完整類型聲明
public:
    void doSomething();
};
#endif

// a.cpp
#include "a.h"
#include "b.h"  // 在實(shí)現(xiàn)文件中包含完整定義

void A::doSomething() {
    b_ptr->doSomething();
}

// b.cpp
#include "b.h"
#include "a.h"  // 在實(shí)現(xiàn)文件中包含完整定義

void B::doSomething() {
    a_ptr->doSomething();
}

2.2 接口分離原則

循環(huán)引用的根本原因是設(shè)計(jì)上的問(wèn)題。通過(guò)重構(gòu)代碼,減少類之間的直接依賴,可以從根本上解決問(wèn)題。例如,可以考慮將共同的功能提取到一個(gè)獨(dú)立的模塊中,或者使用接口或抽象類來(lái)解耦類之間的關(guān)系 

假設(shè) A 和 B 之間有很強(qiáng)的依賴關(guān)系,可以通過(guò)引入一個(gè)中間類 C 來(lái)解耦: 

引入類C 

// C.h
#ifndef C_H
#define C_H

class C {
public:
    virtual void doSomething() = 0;
    virtual ~C() = default;
};

#endif // C_H

類A 

// A.h
#ifndef A_H
#define A_H

#include "C.h"  // 只依賴于 C

class A:public C
{
public:
    C* m_Pc;;
public:
    void setProcessor(C* p) { m_Pc = p; }
    void doWork() { m_Pc->doSomething(); }

    void doSomething() override
    {
        std::cout << "A do something" << std::endl;
    }
};

#endif // A_H

類B 

// B.h
#ifndef B_H
#define B_H

#include "C.h"  // 只依賴于 C

class B : public C
{
public:
    C* m_Pc;;
public:
    void setProcessor(C* p) { m_Pc = p; }
    void doWork() { m_Pc->doSomething(); }

public:
    void doSomething() override
    {
        std::cout << "B Do Something" << std::endl;
    }
};
#endif // B_H

main函數(shù)使用 

#include <iostream>
#include "a.h"
#include "b.h"
#include "c.h"
int main()
{
        {
                C* pC = new B();
                A a;
                a.setProcessor(pC);
                a.doWork();
        }
        {
                C* pC = new A();
                B b;
                b.setProcessor(pC);
                b.doWork();
        }
        return 0;
}

運(yùn)行main函數(shù),a.dowork輸出是B的內(nèi)容,b.dowork是A的內(nèi)容。 

2.3 PIMPL模式

PIMPL模式不能直接解決循環(huán)依賴問(wèn)題,但是這種做法很常見(jiàn),所以這里簡(jiǎn)單介紹下 

PIMPL(Pointer to IMPLementation,指向?qū)崿F(xiàn)的指針)模式是一種用于隱藏類的實(shí)現(xiàn)細(xì)節(jié)的設(shè)計(jì)模式。它通過(guò)將類的私有成員和實(shí)現(xiàn)細(xì)節(jié)移到一個(gè)獨(dú)立的實(shí)現(xiàn)類中,并在頭文件中只保留一個(gè)指向該實(shí)現(xiàn)類的指針,PIMPL 模式的核心思想是將類的接口與其實(shí)現(xiàn)分離。 

使用 PIMPL 模式重構(gòu)代碼 :

類A 

// A.h
#ifndef A_H
#define A_H

class A {
public:
    A();
    ~A();
    void doSomething();

private:
    class Impl;  // 前向聲明實(shí)現(xiàn)類
    std::unique_ptr<Impl> pImpl;  // 指向?qū)崿F(xiàn)類的智能指針
};

#endif // A_H

// A.cpp
#include "A.h"
#include "B.h"  // 只在 .cpp 文件中包含 B 的頭文件

class A::Impl {
public:
    B* m_B;  // 實(shí)現(xiàn)類中持有 B 的指針
    void doSomething() {
        if (m_B) {
            m_B->doSomething();
        }
    }
};

A::A() : pImpl(std::make_unique<Impl>()) {
    pImpl->m_B = nullptr;
}

A::~A() = default;

void A::doSomething() {
    pImpl->doSomething();
}

類B 

// B.h
#ifndef B_H
#define B_H
class B {
public:
    B(); 
    ~B();
    void doSomething();

private:
    class Impl;  // 前向聲明實(shí)現(xiàn)類
    std::unique_ptr<Impl> pImpl;  // 指向?qū)崿F(xiàn)類的智能指針
};

#endif // B_H

// B.cpp
#include "B.h"
#include "A.h"  // 只在 .cpp 文件中包含 A 的頭文件

class B::Impl {
public:
    A* m_A;  // 實(shí)現(xiàn)類中持有 A 的指針
    void doSomething() {
        if (m_A) {
            m_A->doSomething();
        }
    }
};

B::B() : pImpl(std::make_unique<Impl>()) {
    pImpl->m_A = nullptr;
}

B::~B() = default;

void B::doSomething() {
    pImpl->doSomething();
}

代碼解析 :

前向聲明:在 A.h 和 B.h 中,我們只前向聲明了各自的實(shí)現(xiàn)類 Impl,而沒(méi)有包含對(duì)方的頭文件。這樣,頭文件之間不再存在直接的依賴關(guān)系,從而避免了循環(huán)引用。 

實(shí)現(xiàn)類在 .cpp 文件中定義:A::Impl 和 B::Impl 的定義被移到了 .cpp 文件中。這意味著只有在編譯時(shí),A.cpp 和 B.cpp 才會(huì)引入對(duì)方的頭文件,而不是在頭文件中直接包含。 

智能指針:我們使用 std::unique_ptr 來(lái)管理 Impl 對(duì)象的生命周期,確保資源的自動(dòng)釋放,避免內(nèi)存泄漏。 

總結(jié)

優(yōu)先使用前向聲明 

當(dāng)只需要指針或引用時(shí),前向聲明是最簡(jiǎn)單的解決方案 

減少編譯依賴,加快編譯速度 

合理拆分頭文件 

將相關(guān)的聲明放在同一個(gè)頭文件中 

避免在頭文件中包含不必要的其他頭文件 

使用接口抽象 

通過(guò)抽象接口解耦具體實(shí)現(xiàn) 

遵循依賴倒置原則 

實(shí)現(xiàn)邏輯放在cpp文件 

頭文件只包含聲明 

具體實(shí)現(xiàn)放在cpp文件中 

使用PIMPL模式 

對(duì)于復(fù)雜的類,考慮使用PIMPL模式 

可以完全隱藏實(shí)現(xiàn)細(xì)節(jié),提供更好的ABI兼容性 

責(zé)任編輯:武曉燕 來(lái)源: CppPlayer
相關(guān)推薦

2009-08-17 08:29:00

c#刪除指定文件

2011-05-24 09:18:59

C++連接mysql數(shù)據(jù)庫(kù)

2011-04-25 09:53:31

C++mysql

2024-12-06 16:00:00

C++頭文件

2009-08-05 13:34:18

C#日期相減

2010-01-15 18:46:08

C++程序代碼

2010-05-24 15:08:46

MySQL訪問(wèn)權(quán)限

2009-09-02 16:21:02

C#解析Html

2010-02-02 13:04:03

C++頭文件

2019-11-26 14:30:20

Spring循環(huán)依賴Java

2021-03-06 19:45:23

項(xiàng)目文件代碼

2010-08-04 17:41:52

掛載NFS

2010-08-02 16:58:08

Flex配置文件

2010-01-25 17:55:38

C++頭文件

2009-08-21 18:02:41

C#快捷鍵

2013-01-09 10:36:28

mysql主從不同步

2009-09-25 14:04:09

Hibernate eHibernate h

2010-04-13 09:50:44

Oracle跟蹤

2011-03-30 17:04:24

MySQL添加用戶

2009-11-06 09:48:40

WCF服務(wù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: av天天澡天天爽天天av | 日韩一区二区三区在线观看 | 波多野结衣亚洲 | 成人精品免费视频 | 久久久久国产成人精品亚洲午夜 | 成人免费小视频 | 色视频在线播放 | 色视频一区二区 | 中文av在线播放 | 国产精品不卡 | 九色综合网 | 欧美一区二区小视频 | 中国美女撒尿txxxxx视频 | 亚洲黄色网址视频 | 中国美女一级黄色片 | 国产一级片网站 | 日韩成人免费 | 一区二区三区久久 | 在线日韩| 日韩精品欧美精品 | 欧洲精品码一区二区三区免费看 | 波多野结衣中文字幕一区二区三区 | 日日操夜夜操天天操 | 国产精品夜间视频香蕉 | 国产精品福利在线 | 黄色大片在线视频 | 日韩欧美国产一区二区 | 中文字幕一区二区三区四区不卡 | 免费黄色在线观看 | 欧美国产日韩精品 | 久久亚洲国产精品 | 日韩精品一区二区三区在线 | 午夜小电影 | 看a级黄色毛片 | 国产成人高清视频 | 国产真实乱全部视频 | 欧美一级网站 | 91精品国产91久久久久久最新 | 亚洲欧美日韩在线不卡 | 国产免费播放视频 | 午夜精品影院 |