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

深入分析C++中聲明與定義的區(qū)別

 更新時間:2014年09月02日 09:23:54   投稿:hebedich  
C++學(xué)了這么多年你知道為什么定義類時,類的定義放在.h文件中,而類的實(shí)現(xiàn)放在cpp文件中。它們?yōu)槭裁茨軌蜿P(guān)聯(lián)到一起呢?你知道什么東西可以放在.h文件中,什么不能。什么東西又可以放在cpp文件中。如果你忘記了或是壓根就不明白,那么讀過此文你會清晰無比?。?/div>

        首先談下聲明與定義的區(qū)別。
        聲明是將一個名稱引入程序。定義提供了一個實(shí)體在程序中的唯一描述。聲明和定義有時是同時存在的。

   如int a;

   extern int b=1;

    只有當(dāng)extern中不存在初始化式是才是聲明。其他情況既是定義也是聲明。

     但是在下列情況下,聲明僅僅是聲明:

    1:僅僅提供函數(shù)原型。如void func(int,int);

    2: extern int a;

    3:class A;

    4:typedef聲明

    5:在類中定義的靜態(tài)數(shù)據(jù)成員的聲明

   如:

class A 
{ 
  public: 
  static int a;//聲明。 
};

   下列情況下 ,定義僅僅是定義:

   1:在類定義之外,定義并初始化一個靜態(tài)數(shù)據(jù)成員。如 A::a=0;

   2:在類外定義非內(nèi)聯(lián)成員函數(shù)。
     聲明僅僅是將一個符號引入到一個作用域。而定義提供了一個實(shí)體在程序中的唯一描述。在一個給定的定義域中重復(fù)聲明一個符號是可以的,但是卻不能重復(fù)定義,否則將會引起編譯錯誤。但是在類中的成員函數(shù)和靜態(tài)數(shù)據(jù)成員卻是例外,雖然在類內(nèi)它們都是聲明,但是也不能有多個。

如:

        明白了聲明與定義的區(qū)別,還需要明白 內(nèi)部鏈接、外部鏈接。只有明白了它們你才會知道開頭提出的問題。

       在編譯時,編譯器只檢測程序語法和函數(shù)、變量是否被聲明。如果函數(shù)未被聲明,編譯器會給出一個警告,但可以生成目標(biāo)文件。而在鏈接程序時,鏈接器會在所有的目標(biāo)文件中找尋函數(shù)的實(shí)現(xiàn)。如果找不到,那到就會報鏈接錯誤碼(Linker Error)。在VC下,這種錯誤一般是:Link 2001錯誤,意思說是說,鏈接器未能找到函數(shù)的實(shí)現(xiàn)。

      鏈接把不同編譯單元產(chǎn)生的符號聯(lián)系起來。有兩種鏈接方式:內(nèi)部鏈接和外部鏈接。

      如果一個符號名對于它的編譯單元來說是局部的,并且在鏈接時不可能與其他編譯單元中的同樣的名稱相沖突,那個這個符號就是內(nèi)部鏈接。內(nèi)部鏈接意味著對此符號的訪問僅限于當(dāng)前的編譯單元中,對其他編譯單元都是不可見的。

       static關(guān)鍵字作用在全局變量時,表示靜態(tài)全局變量。但是作用域僅僅在當(dāng)前文件作用域內(nèi)。其他文件中即使使用extern聲明也是無法使用的。const也類似。

       帶有static、const關(guān)鍵字和枚舉類型的連接是內(nèi)部的。

       具有內(nèi)部鏈接的符號無法作用于當(dāng)前文件外部,要讓其影響程序的其他部分,可以將其放在.h文件中。此時在所有包含此.h文件的源文件都有自己的定義且互不影響。

       類的定義具有內(nèi)部鏈接,由于它是定義,因此在同一編譯單元中不能重復(fù)出現(xiàn)。如果需要在其他編譯單元使用,類必須被定義在頭文件且被其他文件包含。僅僅在其他文件中使用class a;聲明是不行的,原因就是類的定義是內(nèi)部鏈接,不會在目標(biāo)文件導(dǎo)出符號。也就不會被其他單元解析它們的未定義符號。理解這一點(diǎn)很重要。

     內(nèi)聯(lián)函數(shù)也具有內(nèi)部鏈接。

      在一個多文件的程序中,如果一個符號在鏈接時可以和其他編譯單元交互,那么這個名稱就有外部鏈接。外部鏈接意味著該定義不僅僅局限在單個編譯單元中。它可以在.o文件中產(chǎn)生外部符號??梢员黄渌幾g單元訪問用來解析它們未定義的符號。因此它們在整個程序中必須是唯一的,否則將會導(dǎo)致重復(fù)定義。

       非內(nèi)聯(lián)成員函數(shù)、非內(nèi)聯(lián)函數(shù)、非靜態(tài)自由函數(shù)都具有外部鏈接。

       內(nèi)聯(lián)函數(shù)之所有具有內(nèi)部鏈接,因?yàn)榫幾g器在可能的時候,會將所有 對函數(shù)的調(diào)用替換為函數(shù)體,不將任何符號寫入.o文件。

       判斷一個符號是內(nèi)部鏈接還是外部鏈接的一個很好的方法就是看該符號是否被寫入.o文件。

       前面說的是定義對鏈接方式的影響,接下來說下聲明對鏈接方式的影響。

       由于聲明只對當(dāng)前編譯單元有用,因此聲明并不將任何東西寫入.o文件。

       如extern int a;

       int func();

       這些聲明本身不會影響到.o文件的內(nèi)容。每一個都只是命名一個外部符號,使當(dāng)前的編譯單元在需要的時候可以訪問相應(yīng)的全局定義。

     函數(shù)調(diào)用會導(dǎo)致一個未定義的符號被寫入到.o文件。如果a在該文件中沒有被使用,那么沒有被寫入到.o文件。而func函數(shù)有對此函數(shù)的調(diào)用。也就會將此符號寫入目標(biāo)文件。此后此.o文件與定義此符號的.o文件被連接在一起,前面未定義的符號被解析。

     上述聲明有可能導(dǎo)致該符號被寫入目標(biāo)文件中。但是以下聲明并不會導(dǎo)致該符號寫入到目標(biāo)文件中。

如:

typedef int Int;
Class A; 
struct s; 
union point; 

 
     它們的鏈接也是內(nèi)部的。

     類聲明和類定義都是內(nèi)部鏈接。只是為當(dāng)前編譯單元所用。

     靜態(tài)的類數(shù)據(jù)成員的定義具有外部鏈接。如

class A 
{ 
  static int a;//聲明。具有內(nèi)部鏈接。 
};

      靜態(tài)數(shù)據(jù)成員a僅僅是一個聲明,但是它的定義A::a=0;卻具有外部鏈接。

     C++對類和枚舉類型的處理方式是不一樣的。比如:在不定義類時可以聲明一個類。但是不能未經(jīng)定義就聲明一個枚舉類型。

     基于以上的分析,我們可以知道:將具有外部鏈接的定義放在頭文件中幾乎都是編程錯誤。因?yàn)槿绻擃^文件中被多個源文件包含,那么就會存在多個定義,鏈接時就會出錯。

     在頭文件中放置內(nèi)部鏈接的定義卻是合法的,但不推薦使用的。因?yàn)轭^文件被包含到多個源文件中時,不僅僅會污染全局命名空間,而且會在每個編譯單元中有自己的實(shí)體存在。大量消耗內(nèi)存空間,還會影響機(jī)器性能。

     const和static修飾的全局變量僅僅在當(dāng)前文件作用域內(nèi)有效。它們具有內(nèi)部鏈接屬性。

    下面列出一些應(yīng)該或是不應(yīng)該寫入頭文件的定義:

//test.h 
#ifndef TEST_H 
#define TEST_H 
  int a;   //a有外部鏈接,不能在頭文件中定義。 
  extern int b=10;//同上。 
  const int c=2;//c具有內(nèi)部鏈接,可以定在頭文件中但應(yīng)該避免。 
  static int d=3;//同上。 
  static void func(){} //同上。 
  void func2(){} //同a。 
  void func3();//可以。僅僅是聲明。并不會導(dǎo)致符號名被寫入目標(biāo)文件。 
class A 
{ 
  public: 
   static int e;//可以,具有內(nèi)部鏈接。 
   int f;//可以,同上。 
   void func4();//聲明,內(nèi)部鏈接。同上。 
}; 
  A::e=10;//不可以在頭文件中包含具有外部鏈接的定義。符號名別寫入目標(biāo)文件。 
  void A:func4()//不可以,類成員函數(shù)。外部連接。 
{ 
 //,...... 
} 
#endif
 

      相信大家現(xiàn)在明白為什么只在類型聲明成員函數(shù),而不實(shí)現(xiàn)它是合法的了。也可以回答為什么類的定義可以放在.h文件中。而類的實(shí)現(xiàn)可以放在同名的cpp文件中。老師以前的介紹是說編譯器會自動尋找同名的cpp文件。其實(shí)是因?yàn)橛捎赾pp文件中存儲的是成員函數(shù)的實(shí)現(xiàn),而成員函數(shù)具有外部鏈接特性,會在目標(biāo)文件產(chǎn)生符號。在此文件中此符號是定義過的。其他調(diào)用此成員函數(shù)的目標(biāo)文件也會產(chǎn)生一個未定的符號。兩目標(biāo)文件連接后此符號就被解析。注意static數(shù)據(jù)成員應(yīng)該放在cpp文件中。而不能放在.h文件。

      有內(nèi)部鏈接的定義可以定義在cpp文件中,并不會影響全局的符號空間 。但是在cpp文件作用域中要避免定義(并不禁止)沒有聲明為靜態(tài)的數(shù)據(jù)和函數(shù),因?yàn)樗鼈兙哂型獠挎溄印?/p>

 int a; 
void func() 
{  
    ...... 
} 

      上述定義具有外部鏈接可能會與全局命名空間的其他符號名稱存在潛在沖突。如果確實(shí)需要使用全局的變量或函數(shù)??梢詾樗鼈兗由蟬tatic關(guān)鍵字。使其作用域局限在當(dāng)前文件內(nèi),具有內(nèi)部鏈接也就不會對全局命名空間產(chǎn)生影響。因?yàn)閮?nèi)聯(lián)函數(shù)和靜態(tài)自由函數(shù)、枚舉以及const類型的數(shù)據(jù)都具有內(nèi)部鏈接,所以它們可以定義在cpp文件中,而不會影響全局命名空間。

      typedef和宏定義不會將符號引入.o文件,它們也可以出現(xiàn)在cpp文件中,不會影響全局命名空間。

      typedef 為一個已存在的類型創(chuàng)建一個別名。而不是創(chuàng)建一個新的類型。它不提供類型安全。如

typedef int IntA; 
typedef int InB;  
 

       在需要IntA的地方使用IntB是不會報錯的。它們可以互相替換。因?yàn)榇宋覀兎Q它不提供類型安全。但是在定義函數(shù)類型時typedef經(jīng)常使用,可以使定義更清晰。

      標(biāo)準(zhǔn)c庫提供一個assert宏,用以保證給定的表達(dá)式值非零。否則便會輸出錯誤信息并終止程序執(zhí)行。只有在程序中沒有定義NDEBUG時,assert才會工作。一旦定義NDEBUG  ,assert語句將會被忽略 。注意與VC中的ASSERT相區(qū)別。ASSERT是vc提供的。當(dāng)_DEBUG被定義時才會起作用。

在vc的DEBUG模式下_DEBUG會被定義。而在RELEASE模式下NDEBUG會被定義。

    好了,相信大家都會明白開頭提出的問題了。如果有不明白的,請務(wù)必留言哦。如有錯誤,也請不吝指正??!

    以上內(nèi)容參考自《Large Scale C++ software design》。

相關(guān)文章

  • C語言實(shí)例梳理講解常用關(guān)鍵字的用法

    C語言實(shí)例梳理講解常用關(guān)鍵字的用法

    關(guān)鍵字是C語言非常重要的一部分,熟練的掌握和使用關(guān)鍵字有助于我們更加熟悉了解C語言,同時C語言的關(guān)鍵字也是面試筆試中常考的內(nèi)容。C語言的關(guān)鍵字共有32個,但并不是每個關(guān)鍵字都有坑,本篇文章將通過理論聯(lián)系實(shí)際的方式為大家講解C語言中易混易錯以及??嫉囊恍╆P(guān)鍵字
    2022-05-05
  • c++分離講解模板的概念與使用

    c++分離講解模板的概念與使用

    人們需要編寫多個形式和功能都相似的函數(shù),因此有了函數(shù)模板來減少重復(fù)勞動;人們也需要編寫多個形式和功能都相似的類,于是 C++ 引人了類模板的概念,編譯器從類模板可以自動生成多個類,避免了程序員的重復(fù)勞動
    2022-04-04
  • C++實(shí)現(xiàn)AVL樹的基本操作指南

    C++實(shí)現(xiàn)AVL樹的基本操作指南

    AVL樹是高度平衡的而二叉樹,它的特點(diǎn)是AVL樹中任何節(jié)點(diǎn)的兩個子樹的高度最大差別為1,下面這篇文章主要給大家介紹了關(guān)于C++實(shí)現(xiàn)AVL樹的相關(guān)資料,需要的朋友可以參考下
    2022-01-01
  • C++中protobuf?的交叉編譯使用詳解

    C++中protobuf?的交叉編譯使用詳解

    為了提高通信效率,可以采用?protobuf?替代?XML?和?Json?數(shù)據(jù)交互格式,protobuf?相對來說數(shù)據(jù)量小,在進(jìn)程間通信或者設(shè)備之間通信能夠提高通信速率。下面介紹?protobuf?在?ARM?平臺上的使用,需要的朋友可以參考下
    2022-07-07
  • c++中關(guān)于int、long、long?long等取值范圍

    c++中關(guān)于int、long、long?long等取值范圍

    這篇文章主要介紹了c++中關(guān)于int、long、long?long等取值范圍,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • Windows安裝配置C/C++(VS2017)OpenSSL開發(fā)環(huán)境配置教程

    Windows安裝配置C/C++(VS2017)OpenSSL開發(fā)環(huán)境配置教程

    這篇文章主要為大家詳細(xì)介紹了Windows安裝配置C/C++,OpenSSL開發(fā)環(huán)境配置教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • Qt學(xué)習(xí)教程之表格控件螞蟻線詳解

    Qt學(xué)習(xí)教程之表格控件螞蟻線詳解

    如果有用過PS的選區(qū)工具應(yīng)該就會知道螞蟻線是什么東西了,就是用來表示選區(qū)的一種虛線,關(guān)鍵還是要動態(tài)的!下面這篇文章主要給大家介紹了關(guān)于Qt學(xué)習(xí)教程之表格控件螞蟻線的相關(guān)資料,需要的朋友可以參考下
    2018-07-07
  • 一文弄懂C語言EOF

    一文弄懂C語言EOF

    在 C語言中,EOF 是一個宏定義,EOF 常常用于文件的輸入輸出中,當(dāng)讀取到文件結(jié)束時,會返回 EOF,本文就詳細(xì)的介紹一下具體使用方法,感興趣的可以一起來了解一下
    2023-05-05
  • C++數(shù)據(jù)結(jié)構(gòu)AVL樹全面分析

    C++數(shù)據(jù)結(jié)構(gòu)AVL樹全面分析

    今天的這一篇博客,我要跟大家介紹一顆樹——AVL樹,它也是一顆二叉搜索樹,它就是在二叉搜索樹中加了一個平衡因子的概念在里面,下面我就來和大家聊一聊這棵樹是個怎么樣的樹
    2021-10-10
  • 詳解C語言通過遞歸與非遞歸實(shí)現(xiàn)蛇形矩陣

    詳解C語言通過遞歸與非遞歸實(shí)現(xiàn)蛇形矩陣

    蛇形矩陣(Snake matrix)是矩陣的一種,常被應(yīng)用在編程題目與數(shù)學(xué)數(shù)列中,需要提取每條斜線里最小的數(shù)字,本篇文章將會通過遞歸和非遞歸來分別實(shí)現(xiàn)蛇形矩陣
    2022-02-02

最新評論

始兴县| 奇台县| 乐安县| 凉山| 邓州市| 鲁甸县| 通州区| 乌拉特前旗| 喀喇| 洱源县| 兴山县| 巢湖市| 怀远县| 宁南县| 晋城| 绥德县| 洱源县| 开阳县| 山阴县| 揭阳市| 大名县| 祁连县| 南城县| 馆陶县| 错那县| 太康县| 浦江县| 凤阳县| 固始县| 博白县| 铜陵市| 象州县| 莎车县| 湖州市| 六枝特区| 山西省| 古田县| 济南市| 太仆寺旗| 苏尼特右旗| 华坪县|