1. inline內(nèi)聯(lián)函數(shù)為什么不能是虛函數(shù)?
虛函數(shù)可以是內(nèi)聯(lián)函數(shù),內(nèi)聯(lián)是可以修飾虛函數(shù)的,但是當(dāng)虛函數(shù)表現(xiàn)多態(tài)性的時(shí)候不能內(nèi)聯(lián)。
理由如下:內(nèi)聯(lián)是在發(fā)生在編譯期間,編譯器會(huì)自主選擇內(nèi)聯(lián),而虛函數(shù)的多態(tài)性在運(yùn)行期,編譯器無法知道運(yùn)行期調(diào)用哪個(gè)代碼,因此虛函數(shù)表現(xiàn)為多態(tài)性時(shí)(運(yùn)行期)不可以內(nèi)聯(lián)。 inline virtual
唯一可以內(nèi)聯(lián)的時(shí)候是:編譯器知道所調(diào)用的對(duì)象是哪個(gè)類(如 Base::who()
),這只有在編譯器具有實(shí)際對(duì)象而不是對(duì)象的指針或引用時(shí)才會(huì)發(fā)生。
2. 編譯器對(duì)inline函數(shù)的處理步驟
- 將 inline 函數(shù)體復(fù)制到 inline 函數(shù)調(diào)用點(diǎn)處;
- 為所用 inline 函數(shù)中的局部變量分配內(nèi)存空間;
- 將 inline 函數(shù)的的輸入?yún)?shù)和返回值映射到調(diào)用方法的局部變量空間中;
- 如果 inline 函數(shù)有多個(gè)返回點(diǎn),將其轉(zhuǎn)變?yōu)?inline 函數(shù)代碼塊末尾的分支(使用 GOTO);
3. 類模板、函數(shù)模板與虛函數(shù)?
4. 為什么要避免頭文件重復(fù)包含呢?
- 在編譯c或c++程序時(shí)候,編譯器首先要對(duì)程序進(jìn)行預(yù)處理,預(yù)處理其中一項(xiàng)工作便是將源程序中 #include的頭文件完整的展開,如果多次包含相同的頭文件,會(huì)導(dǎo)致編譯器在后面的編譯步驟多次編譯該頭文件,工程代碼量小還好,工程量一大會(huì)使整個(gè)項(xiàng)目編譯速度變的緩慢,后期的維護(hù)修改變得困難。
- 第一點(diǎn)講的頭文件重復(fù)包含的壞處其實(shí)還能忍,但是頭文件重復(fù)包含帶來的最大壞處是會(huì)使程序在編譯鏈接的時(shí)候崩潰。
那么如何避免它呢?
通常有兩種做法:條件編譯和**#pragma once**。
區(qū)別:
- #ifndef 是通過定義獨(dú)一無二的宏來避免重復(fù)引入的,這意味著每次引入頭文件都要進(jìn)行識(shí)別,所以效率不高。但考慮到 C 和 C++ 都支持宏定義,所以項(xiàng)目中使用 #ifndef 規(guī)避可能出現(xiàn)的“頭文件重復(fù)引入”問題,不會(huì)影響項(xiàng)目的可移植性。
- 和 ifndef 相比,#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è)具體的文件,而無法向 #ifndef 那樣僅作用于指定的一段代碼。
5. 聲明與定義
**“聲明”:**只是聲明某個(gè)符號(hào)(變量或函數(shù))的存在,即告訴編譯器,這個(gè)符號(hào)是在其他文件中定義的,我這里先用著,你鏈接的時(shí)候再到別的地方去找找看它到底是什么吧。
**“定義”:**則是要按C++語(yǔ)法完整地定義一個(gè)符號(hào)(變量或者函數(shù)),告訴編譯器在此處分配存儲(chǔ)空間建立變量和函數(shù)。
**頭文件的作用:**就是被其他的.cpp包含進(jìn)去的, 本身并不參與編譯。但實(shí)際上,它們的內(nèi)容卻在多個(gè).cpp文件中得到了編譯。通過"定義只能有一次”的規(guī)則,很容易可以得出:頭文件中應(yīng)該只放變量和函數(shù)的聲明,而不能放它們的定義。因?yàn)橐粋€(gè)頭文件的內(nèi)容實(shí)際上是會(huì)被引 入到多個(gè)不同的.cpp文件中的,并且它們都會(huì)被編譯。放聲明當(dāng)然沒事,如果放了定義,那么也就相當(dāng)于在多個(gè).cpp文件中出現(xiàn)了對(duì)同一個(gè)符號(hào)(變量或函數(shù))的定義,因此就會(huì)報(bào)“重復(fù)定義的錯(cuò)誤”。
**總結(jié):**聲明是將一個(gè)名稱引入程序;定義提供了一個(gè)實(shí)體(類型、變量、對(duì)象、函數(shù))在程序中的唯一描述。
**所以:**一個(gè)符號(hào),在整個(gè)程序中可以被聲明多次,但只允許被定義一次。
6. 內(nèi)部鏈接與外部鏈接
1. 內(nèi)部鏈接:內(nèi)部鏈接意味著對(duì)符號(hào)名的訪問僅限于當(dāng)前編譯單元。即:對(duì)于任何其他編譯單元都是不可見的,在鏈接的時(shí)候不會(huì)與其它編譯單元中同樣的名稱相沖突,則這個(gè)符號(hào)具有內(nèi)部鏈接。
? 具體有:
- 靜態(tài)(static)全局變量的定義、靜態(tài)自由函數(shù)的定義、靜態(tài)友元函數(shù)的定義;
- 類的聲明與定義;
- 內(nèi)聯(lián)函數(shù)定義;
- Union共同體/結(jié)構(gòu)體/枚舉類型定義;
- const常量定義;
- 各種聲明;
C++又補(bǔ)充規(guī)定,extern const聯(lián)合修飾時(shí),extern將壓制const的內(nèi)部鏈接屬性。
用內(nèi)部鏈接定義的一個(gè)重要的例子就是類的定義。類的定義如下。因此,它不能夠在同一作用域的編譯單元內(nèi)重復(fù)定義。如果需要在其他編譯單元使用,類必須被定義在頭文件且被其他文件包含。僅僅在其他文件中使用class Point;聲明是不行的,原因就是類的定義是內(nèi)部鏈接,不會(huì)在目標(biāo)文件導(dǎo)出符號(hào)。也就不會(huì)被其他單元解析它們的未定義符號(hào)。
class Point{
int d_x; // 內(nèi)部鏈接
int d_y;
public:
Point(int x,int y):d_x(x),d_y(y){} // 內(nèi)部鏈接
int x() const{return d_x;} // 內(nèi)部鏈接
int y() const{return d_y;} // 內(nèi)部鏈接
};
因此:具有內(nèi)部鏈接的符號(hào)無法作用于當(dāng)前文件外部,要讓其影響程序的其他部分,可以將其放在.h文件中。此時(shí)在所有包含此.h文件的源文件都有自己的定義且互不影響。
2. 外部鏈接:外部鏈接意味著這個(gè)定義不局限于單個(gè)的編譯單元。在.o文件中,具有外部鏈接的定義產(chǎn)生外部符號(hào),這些外部符號(hào)可以被所有其他編譯單元訪問,用來解析其他編譯單元中未定義的符號(hào),即:一個(gè)名稱在鏈接時(shí)可以和其他編譯單元交互,那么這個(gè)名稱就具有外部鏈接。
因此:因此它們?cè)谡麄€(gè)程序中必須是唯一的,否則將會(huì)導(dǎo)致重復(fù)定義
? 具體有:
? 1.類的非內(nèi)聯(lián)函數(shù)(包括成員函數(shù)和靜態(tài)成員函數(shù))的定義
? 2.類的靜態(tài)成員變量的定義
? 3.名字空間或全局非靜態(tài)的自由函數(shù),非靜態(tài)變量,非友元函數(shù)的定義
class A
{
static int a; // 類的靜態(tài)成員聲明,內(nèi)部鏈接
void fun(); // 類的非內(nèi)聯(lián)成員函數(shù)聲明,內(nèi)部鏈接
static void fun2(); // 類的非內(nèi)聯(lián)靜態(tài)成員函數(shù)聲明,內(nèi)部鏈接
void fun2(){...}; // 類內(nèi)實(shí)現(xiàn)函數(shù)定義,若為內(nèi)聯(lián)則為內(nèi)部鏈接,若為非內(nèi)聯(lián)則為外部鏈接
}
int A::a = 1; // 類的靜態(tài)成員定義,外部鏈接
void A::fun(){...}; // 類的非內(nèi)聯(lián)成員函數(shù)定義,外部鏈接
static void A::fun2(){...}; //類的非內(nèi)聯(lián)靜態(tài)成員函數(shù)定義,外部鏈接
namespace A{...} // 名字空間定義,外部鏈接
void fun3(){...}; // 全局非靜態(tài)自由函數(shù)定義,外部鏈接
int b; // 全局非靜態(tài)變量,外部鏈接
所以,擁有外部鏈接的實(shí)體如果放在頭文件中并且被多個(gè).cpp文件包含,可能就會(huì)出現(xiàn)鏈接沖突錯(cuò)誤,因?yàn)槊總€(gè)包含這個(gè)擁有外部鏈接實(shí)體的.cpp都會(huì)分配空間,當(dāng)多個(gè)編譯單元鏈接的時(shí)候,連接器就會(huì)面對(duì)多個(gè)相同的名字,無法正常鏈接到正確的對(duì)象。
因此:由于cpp文件中存儲(chǔ)的是成員函數(shù)的實(shí)現(xiàn),而成員函數(shù)具有外部鏈接特性,會(huì)在目標(biāo)文件產(chǎn)生符號(hào)。在此文件中此符號(hào)是定義過的。其他調(diào)用此成員函數(shù)的目標(biāo)文件也會(huì)產(chǎn)生一個(gè)未定的符號(hào)。兩目標(biāo)文件連接后此符號(hào)就被解析。
判斷一個(gè)符號(hào)是內(nèi)部鏈接還是外部鏈接的一個(gè)很好的方法就是看該符號(hào)是否被寫入.o文件,由于聲明只對(duì)當(dāng)前編譯單元有用,因此聲明并不將任何東西寫入.o文件。
宏是內(nèi)部鏈接還是外部鏈接
都不是,宏在預(yù)處理環(huán)節(jié)時(shí)就被替換掉了,而內(nèi)部鏈接與外部鏈接是針對(duì)編譯環(huán)節(jié)與鏈接環(huán)節(jié)而言的文章來源:http://www.zghlxwxcb.cn/news/detail-832165.html
7. 在.h中和.cpp中include頭文件有什么區(qū)別
在 .h 里面 include 的好處是:如果全部在一個(gè).h, 那么每個(gè).c/.cpp
文件只需要一個(gè)#include
語(yǔ)句這樣不僅輸入量減少,而且代碼也美觀多了代碼也主次分明了畢竟。文章來源地址http://www.zghlxwxcb.cn/news/detail-832165.html
到了這里,關(guān)于inline內(nèi)聯(lián)函數(shù)為什么不能是虛函數(shù)?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!