欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

解析C++多文件編程問(wèn)題

 更新時(shí)間:2021年10月26日 15:56:31   作者:人生有跡  
在某些場(chǎng)景中,考慮到編譯效率和可移植性,#pragma once 和 #ifndef 經(jīng)常被結(jié)合使用來(lái)避免頭文件被 重復(fù)引入,這里介紹用 _Pragma 操作符避免頭文件重復(fù)引入的問(wèn)題,感興趣的朋友跟隨小編一起看看吧

一、多文件編程是什么

為了方便后期的維護(hù),分散代碼應(yīng)遵循一個(gè)基本原則:實(shí)現(xiàn)相同功能的代碼應(yīng)存儲(chǔ)在一個(gè)文件中。

C++ 代碼文件根據(jù)后綴名的不同,大致可以分為如下幾類:

.h:頭文件
.hpp:頭文件,header plus plus 的縮寫(xiě),混雜著 .h 的聲明 .cpp 的定義,OpenCV 采用
.cpp:源文件,windows
.cc:源文件,Unix/Linux

對(duì)于一些系統(tǒng)提供的庫(kù),出于版權(quán)和保密考慮,大多是已經(jīng)編譯好的二進(jìn)制文件,可能僅包含 .h 文件。

// student.h
class Student{
    // ...
};
// student.cc
#include "sudent.h"
// Student 定義
// main.cc
#include "student.h"

int main(){
    // ...
}

二、如何防治頭文件被重復(fù)引入

1. 使用宏定義避免

#ifndef _NAME_H
#define _NAME_H

//頭文件內(nèi)容

#endif

_NAME_H 是宏的名稱。需要注意的是,這里設(shè)置的宏名必須是獨(dú)一無(wú)二的,不要和項(xiàng)目中其他宏的名稱相同。

// student.h
#ifndef _STUDENT_H
#define _STUDENT_H
class Student{
    // ...
};
#endif

2. 使用 #pragma once 避免

使用 #pragma one 指令,將其附加到指定文件的最開(kāi)頭位置,則該文件就只會(huì)被 #include 一次。

#ifndef 是通過(guò)定義獨(dú)一無(wú)二的宏來(lái)避免重復(fù)引入的,這意味著每次引入頭文件都要進(jìn)行識(shí)別,所以 效率不高。但考慮到 C 和 C++ 都支持宏定義,所以項(xiàng)目中使用 #ifndef 規(guī)避可能出現(xiàn)的“頭文件重復(fù)引入”問(wèn)題,不會(huì)影響項(xiàng)目的可移植性。

#pragma once 不涉及宏定義,當(dāng)編譯器遇到它時(shí)會(huì)立刻知道當(dāng)前文件只引入一次,所以效率很高。但值得一提的是,并不是每個(gè)版本的編譯器都能識(shí)別 #pragma once 指令,一些較老版本的編譯器就不支持該指令(執(zhí)行時(shí)會(huì)發(fā)出警告,但編譯會(huì)繼續(xù)進(jìn)行),即 #pragma once 指令的兼容性不是很好。

#pragma once 只能作用于某個(gè)具體的文件,而無(wú)法向 #ifndef 那樣僅作用于指定的一段代碼。

#pragma once
class Student{
    // ...
};

3. 使用 _Pragma 操作符

_Pragma 操作符可以看做是 #pragma 的增強(qiáng)版,不僅可以實(shí)現(xiàn) #pragma 所有的功能,還能和宏搭配使用。

這里僅介紹用 _Pragma 操作符避免頭文件重復(fù)引入。

當(dāng)處理頭文件重復(fù)引入問(wèn)題時(shí),可以將如下語(yǔ)句添加到相應(yīng)文件的開(kāi)頭:

_Pragma("once")

_Pragma("once");
class Student{
    // ...
};

在某些場(chǎng)景中,考慮到編譯效率和可移植性,#pragma once 和 #ifndef 經(jīng)常被結(jié)合使用來(lái)避免頭文件被 重復(fù)引入。比如說(shuō):

#pragma once
#ifndef _STUDENT_H
#define _STUDENT_H
class Student{
    // ...
};
#endif

當(dāng)編譯器可以識(shí)別 #pragma once 時(shí),則整個(gè)文件僅被編譯一次;反之,即便編譯器不識(shí)別 #pragma once 指令,此時(shí)仍有 #ifndef 在發(fā)揮作用。

三、命名空間如何應(yīng)用在多文件編程中

當(dāng)進(jìn)行多文件編程時(shí),命名空間常位于 .h 頭文件中。

// student_li.h
#ifndef _STUDENT_LI_H
#define _STUDENT_LI_H
namespace Li{
    class Student{
        // ...
    };
}
#endif
// student_li.cc
#include "student_li.h"
#include <iostream>
void Li::Student::display(){

}
// student_han.h
#ifndef _STUDENT_HAN_H
#define _STUDENT_HAN_H
namespace Han{
    class Student{
        // ...
    };
}
#endif
// student_han.cpp
#include "student_han.h"
#include <iostream>
void Han::Student::display(){}

注意,當(dāng)類的聲明位于指定的命名空間中時(shí),如果要在類的外部實(shí)現(xiàn)其成員方法,需同時(shí)注明所在命名空間名 和類名(例如本項(xiàng)目中的 Li::Student::display() )。

四、const常量如何在多文件編程中使用

用 const 修飾的變量必須在定義的同時(shí)進(jìn)行初始化操作(除非用 extern 修飾)

C++ 中 const 關(guān)鍵字的功能有 2 個(gè),除了表明其修飾的變量為常量外,還將所修飾變量的可見(jiàn)范圍 限制為當(dāng)前文件。這意味著,除非 const 常量的定義和 main 主函數(shù)位于同一個(gè) .cpp 文件,否則該 const 常量只能在其所在的 .cpp 文件中使用。

那么,如何定義 const 常量,才能在其他文件中使用呢?

1. 將 const 常量定義在 .h 頭文件中

// demo.h
#ifndef _DEMO_H
#define _DEMO_H
const int num = 10;
#endif
// main.cc
#include <iostream>
#include "demo.h"
int main(){
    std::cout << num << std::endl;
    return 0;
}

2. 借助 extern 先聲明再定義 const 常量

借助 extern 關(guān)鍵字,const 常量的定義也可以遵循“聲明在 .h 文件,定義在 .cpp 文件”。

// demo.h
#ifndef _DEMO_H
#define _DEMO_H
extern const int num;   // 聲明 const 常量
#endif
// demo.cc
#include "demo.h"
const int num = 10;
// main.cpp
#include <iostream>
#include "demo.h"
int main(){
    std::cout << num << std::endl;
    return 0;
}

3. 借助 extern 直接定義 const 常量

C++ 編譯器在運(yùn)行項(xiàng)目時(shí),會(huì)在預(yù)處理階段直接將 #include 引入的頭文件替換成該頭文件中的內(nèi)容(復(fù)制粘貼),因此可以對(duì)上節(jié)代碼做修改:

// demo.cpp
extern const int num = 10;
// main.cpp
#include <iostream>
extern const int num;
int main(){
    std::cout << num << std::endl;
    return 0;
}

五、多文件項(xiàng)目如何用 g++ 命令執(zhí)行

在 Linux 平臺(tái)上,雖然也有很多可用的 C++ IDE,但執(zhí)行 C++ 程序更常采用的方式是使用 g++ 命令。

除此之外,Linux 平臺(tái)還經(jīng)常編寫(xiě) makefile 來(lái)運(yùn)行規(guī)模較大的 C++ 項(xiàng)目。

C++ 程序的執(zhí)行過(guò)程分為 4 步,依次是預(yù)處理、編譯、 匯編和鏈接。在執(zhí)行 C++ 項(xiàng)目時(shí),頭文件是不需要經(jīng)歷以上這 4 個(gè)階段的,只有項(xiàng)目中的所有源文件才必須經(jīng)歷這 4 個(gè)階段。

假設(shè)有這個(gè)一個(gè) C++ 項(xiàng)目

// studetn.h
class Student{
    // ...
};
// student.cc
#include <iostream>
#include "student.h"
void Student::say(){
    std::cout << name << "的年齡是" << age << ",成績(jī)是" << score << std::endl;
}
// main.cc
#include "student.h"
int main(){
    Student *pStu = new Student;
    // ...
    delete pStu;
    return 0;
}

預(yù)處理階段,執(zhí)行如下命令:

[root@bogon ~]# g++ -E main.cc -o main.i
[root@bogon ~]# g++ -E student.cc -o student.i

  • -E 選項(xiàng)用于限定 g++ 編譯器只進(jìn)行預(yù)處理而不進(jìn)行后續(xù)的 3 個(gè)階段;
  • -o 選項(xiàng)用于指定生成文件的名稱。

編譯階段,進(jìn)一步生成響應(yīng)的匯編代碼文件:

[root@bogon ~]# g++ -S main.i -o main.s
[root@bogon ~]# g++ -S student.i -o student.s

  • -S 選項(xiàng)用于限定 g++ 編譯器對(duì)指定文件進(jìn)行編譯,得到的匯編代碼文件通常以“.s”作為后綴名。

將匯編文件轉(zhuǎn)換成可執(zhí)行的機(jī)器命令:

[root@bogon ~]# g++ -c main.s -o main.o
[root@bogon ~]# g++ -c student.s -o student.o

  • 如果不用 -o 指定可執(zhí)行文件的名稱,默認(rèn)情況下會(huì)生成 a.out 可執(zhí)行文件。Linux 系統(tǒng)并不以文件的擴(kuò) 展名開(kāi)分區(qū)文件類型,所以 a.out 和 student.exe 都是可執(zhí)行文件,只是文件名稱有區(qū)別罷了。

最終執(zhí)行:

[root@bogon ~]# ./student.exe

從頭開(kāi)始直接生成可執(zhí)行文件:

[root@bogon ~]# g++ main.cpp student.cpp -o student.exe

六、多文件編程的底層原理

實(shí)際上,在編譯階段,編輯器會(huì)對(duì)源文件生成一個(gè)符號(hào)表,源文件中看不到的定義的符號(hào)就會(huì)存在這個(gè)表中。在鏈接階段,編譯器會(huì)在別的目標(biāo)文件中尋找這個(gè)符號(hào)的定義,如何沒(méi)有找到,會(huì)出現(xiàn)鏈接錯(cuò)誤。

定義,指的是就是將某個(gè)符號(hào)完整的描述清楚,它是變量還是函數(shù),變量類型以及變量值是多少,函數(shù)的參數(shù)有哪些以及返回值是什么等等;而“聲明”的作用僅是告訴編譯器該符號(hào)的存在,至于該符號(hào)的具體的含義,只有等鏈接的時(shí)候才能知道。

C++ 中一個(gè)符號(hào)允許被聲明多次,但只能被定義一次。

基于聲明和定義的不同,才有了多文件編程的出現(xiàn)。

所謂的頭文件,其實(shí)它的內(nèi)容跟 .cpp 文件中的內(nèi)容是一樣的,都是 C++ 的源代碼,唯一的區(qū)別在于頭文件不 用被編譯。我們把所有的函數(shù)聲明全部放進(jìn)一個(gè)頭文件中,當(dāng)某一個(gè) .cpp 源文件需要時(shí),可以通過(guò) #include 宏命令直接將頭文件中的所有內(nèi)容引入到 .cpp 文件中。這樣,當(dāng) .cpp 文件被編譯之前(也就是預(yù)處理階段),使用 #include 引入的 .h 文件就會(huì)替換成該文件中的所有聲明。

通常一個(gè)頭文件的內(nèi)容會(huì)被引入到多個(gè)不同的源文件中,并且都會(huì)被編譯,所以頭文件中一般只存放變量或者函數(shù)的聲明,不要放定義。但存在3種情況屬于定義范疇,但應(yīng)該放在 .h 文件種:

  • 頭文件中定義 const 對(duì)象、static 對(duì)象頭文件中定義內(nèi)聯(lián)函數(shù),編譯器必須在編譯時(shí)就找到內(nèi)聯(lián)函數(shù)的完成定義頭文件中可以定義類。
  • 類的內(nèi)部通常包含成員變量和成員函數(shù),成員變量是要等到具體的對(duì)象被創(chuàng)建時(shí)才會(huì)被定義(分配空間),但成員函數(shù)卻是需要在一開(kāi)始就被定義的,這也就是類的實(shí)現(xiàn)。
  • 通常的做法是將類的定義放在頭文件中,而把成員函數(shù)的實(shí)現(xiàn)代碼放在一個(gè) .cpp 文件中。也可以直接實(shí)現(xiàn)在類內(nèi),作為內(nèi)聯(lián)函數(shù)。

到此這篇關(guān)于C++多文件編程的文章就介紹到這了,更多相關(guān)C++多文件編程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語(yǔ)言算法練習(xí)之抓交通肇事犯

    C語(yǔ)言算法練習(xí)之抓交通肇事犯

    這篇文章主要該大家分享C語(yǔ)言算法抓交通肇事犯的練習(xí),文章主要通過(guò)描述抓交通肇事犯得問(wèn)題然后確定程序框架將結(jié)果運(yùn)算出來(lái),下面來(lái)看詳細(xì)內(nèi)容吧,需要的朋友可以參考一下
    2022-03-03
  • C++模擬實(shí)現(xiàn)string的示例代碼

    C++模擬實(shí)現(xiàn)string的示例代碼

    這篇文章主要為大家詳細(xì)介紹了C++模擬實(shí)現(xiàn)string的相關(guān)資料,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C++有一定的幫助,需要的可以參考一下
    2022-11-11
  • __stdcall 和 __cdecl 的區(qū)別淺析

    __stdcall 和 __cdecl 的區(qū)別淺析

    __stdcall 和 __cdecl 的區(qū)別淺析,需要的朋友可以參考一下
    2013-03-03
  • C語(yǔ)言實(shí)現(xiàn)一個(gè)閃爍的圣誕樹(shù)

    C語(yǔ)言實(shí)現(xiàn)一個(gè)閃爍的圣誕樹(shù)

    本文詳細(xì)講解了C語(yǔ)言實(shí)現(xiàn)一個(gè)閃爍的圣誕樹(shù),文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-12-12
  • C++實(shí)現(xiàn)LeetCode(312.打氣球游戲)

    C++實(shí)現(xiàn)LeetCode(312.打氣球游戲)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(312.打氣球游戲),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C++重載運(yùn)算符實(shí)現(xiàn)分?jǐn)?shù)加減乘除

    C++重載運(yùn)算符實(shí)現(xiàn)分?jǐn)?shù)加減乘除

    這篇文章主要為大家詳細(xì)介紹了C++重載運(yùn)算符實(shí)現(xiàn)分?jǐn)?shù)加減乘除,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的推箱子小游戲

    C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的推箱子小游戲

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的推箱子小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • QT開(kāi)發(fā)應(yīng)用程序的歡迎界面實(shí)例

    QT開(kāi)發(fā)應(yīng)用程序的歡迎界面實(shí)例

    下面小編就為大家?guī)?lái)一篇QT開(kāi)發(fā)應(yīng)用程序的歡迎界面實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • Opencv基于CamShift算法實(shí)現(xiàn)目標(biāo)跟蹤

    Opencv基于CamShift算法實(shí)現(xiàn)目標(biāo)跟蹤

    這篇文章主要為大家詳細(xì)介紹了Opencv基于CamShift算法實(shí)現(xiàn)目標(biāo)跟蹤,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • C/C++經(jīng)典楊輝三角問(wèn)題解決方案

    C/C++經(jīng)典楊輝三角問(wèn)題解決方案

    楊輝三角形,又稱帕斯卡三角形、賈憲三角形、海亞姆三角形,它的排列形如三角形。本文將為大家介紹通過(guò)C++/C語(yǔ)言實(shí)現(xiàn)打印楊輝三角形的示例代碼,需要的可以參考一下
    2023-02-02

最新評(píng)論