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

解析C++多文件編程問題

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

一、多文件編程是什么

為了方便后期的維護,分散代碼應遵循一個基本原則:實現(xiàn)相同功能的代碼應存儲在一個文件中。

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

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

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

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

int main(){
    // ...
}

二、如何防治頭文件被重復引入

1. 使用宏定義避免

#ifndef _NAME_H
#define _NAME_H

//頭文件內容

#endif

_NAME_H 是宏的名稱。需要注意的是,這里設置的宏名必須是獨一無二的,不要和項目中其他宏的名稱相同。

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

2. 使用 #pragma once 避免

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

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

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

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

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

3. 使用 _Pragma 操作符

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

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

當處理頭文件重復引入問題時,可以將如下語句添加到相應文件的開頭:

_Pragma("once")

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

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

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

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

三、命名空間如何應用在多文件編程中

當進行多文件編程時,命名空間常位于 .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(){}

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

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

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

C++ 中 const 關鍵字的功能有 2 個,除了表明其修飾的變量為常量外,還將所修飾變量的可見范圍 限制為當前文件。這意味著,除非 const 常量的定義和 main 主函數(shù)位于同一個 .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 關鍵字,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++ 編譯器在運行項目時,會在預處理階段直接將 #include 引入的頭文件替換成該頭文件中的內容(復制粘貼),因此可以對上節(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;
}

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

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

除此之外,Linux 平臺還經(jīng)常編寫 makefile 來運行規(guī)模較大的 C++ 項目。

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

假設有這個一個 C++ 項目

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

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

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

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

編譯階段,進一步生成響應的匯編代碼文件:

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

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

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

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

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

最終執(zhí)行:

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

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

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

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

實際上,在編譯階段,編輯器會對源文件生成一個符號表,源文件中看不到的定義的符號就會存在這個表中。在鏈接階段,編譯器會在別的目標文件中尋找這個符號的定義,如何沒有找到,會出現(xiàn)鏈接錯誤。

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

C++ 中一個符號允許被聲明多次,但只能被定義一次。

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

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

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

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

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

相關文章

  • C語言算法練習之抓交通肇事犯

    C語言算法練習之抓交通肇事犯

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

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

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

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

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

    C語言實現(xiàn)一個閃爍的圣誕樹

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

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

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

    C++重載運算符實現(xiàn)分數(shù)加減乘除

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

    C語言實現(xiàn)簡單的推箱子小游戲

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

    QT開發(fā)應用程序的歡迎界面實例

    下面小編就為大家?guī)硪黄猀T開發(fā)應用程序的歡迎界面實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • Opencv基于CamShift算法實現(xiàn)目標跟蹤

    Opencv基于CamShift算法實現(xiàn)目標跟蹤

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

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

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

最新評論