C++std命名空間和頭文件詳解

一個中大型軟件往往由多名程序員共同開發,會使用大量的變量和函數,不可避免地會出現變量或函數的命名沖突。當所有人的代碼都測試通過,沒有問題時,將它們結合到一起就有可能會出現命名沖突。

例如小李和小韓都參與了一個文件管理系統的開發,它們都定義了一個全局變量 fp,用來指明當前打開的文件,將他們的代碼整合在一起編譯時,很明顯編譯器會提示 fp 重復定義(Redefinition)錯誤。

為了解決合作開發時的命名沖突問題,cpp引入了命名空間(Namespace)的概念。請看下面的例子:

namespace Li{  //小李的變量定義FILE fp = NULL;
}
namespace Han{  //小韓的變量定義FILE fp = NULL
}
小李與小韓各自定義了以自己姓氏為名的命名空間,此時再將他們的 fp 變量放在一起編譯就不會有任何問題。

namespace 是C++中的關鍵字,用來定義一個命名空間,語法格式為:

namespace name{//variables, functions, classes
}

name是命名空間的名字,它里面可以包含變量、函數、類、typedef、#define 等,最后由{ }包圍。

使用變量、函數時要指明它們所在的命名空間。以上面的 fp 變量為例,可以這樣來使用:

Li::fp = fopen("one.txt", "r"); //使用小李定義的變量 fp
Han::fp = fopen("two.txt", "rb+"); //使用小韓定義的變量 fp

::是一個新符號,稱為域解析操作符,在C++中用來指明要使用的命名空間。

除了直接使用域解析操作符,還可以采用 using關鍵字聲明,例如:

using Li::fp;
fp = fopen("one.txt", "r"); //使用小李定義的變量 fp
Han :: fp = fopen("two.txt", "rb+"); //使用小韓定義的變量 fp

在代碼的開頭用using聲明了?Li::fp,它的意思是,using 聲明以后的程序中如果出現了未指明命名空間的 fp,就使用 Li::fp;但是若要使用小韓定義的 fp,仍然需要 Han::fp。

using 聲明不僅可以針對命名空間中的一個變量,也可以用于聲明整個命名空間,例如:

using namespace Li;
fp = fopen("one.txt", "r");? //使用小李定義的變量 fp
Han::fp = fopen("two.txt", "rb+");? //使用小韓定義的變量 fp

?

如果命名空間 Li 中還定義了其他的變量,那么同樣具有 fp 變量的效果。在 using 聲明后,如果有未具體指定命名空間的變量產生了命名沖突,那么默認采用命名空間 Li 中的變量。

命名空間內部不僅可以聲明或定義變量,對于其它能在命名空間以外聲明或定義的名稱,同樣也都能在命名空間內部進行聲明或定義,例如類、函數、typedef、#define 等都可以出現在命名空間中。

站在編譯和鏈接的角度,代碼中出現的變量名、函數名、類名等都是一種符號(Symbol)。有的符號可以指代一個內存位置,例如變量名、函數名;有的符號僅僅是一個新的名稱,例如 typedef 定義的類型別名。

下面來看一個命名空間完整示例代碼:

#include <stdio.h>//將類定義在命名空間中
namespace Diy{class Student{public:char *name;int age;float score;public:void say(){printf("%s的年齡是 %d,成績是 %f\n", name, age, score);}};
}int main(){Diy::Student stu1;stu1.name = "小明";stu1.age = 15;stu1.score = 92.5f;stu1.say();return 0;
}
運行結果:

小明的年齡是 15,成績是 92.500000

?

早期的 C++ 還不完善,不支持命名空間,沒有自己的編譯器,而是將 C++ 代碼翻譯成C代碼,再通過C編譯器完成編譯。這個時候的 C++ 仍然在使用C語言的庫,stdio.h、stdlib.h、string.h 等頭文件依然有效;此外 C++ 也開發了一些新的庫,增加了自己的頭文件,例如:

  • iostream.h:用于控制臺輸入輸出頭文件。
  • fstream.h:用于文件操作的頭文件。
  • complex.h:用于復數計算的頭文件。


和C語言一樣,C++ 頭文件仍然以.h為后綴,它們所包含的類、函數、宏等都是全局范圍的。

后來 C++ 引入了命名空間的概念,計劃重新編寫庫,將類、函數、宏等都統一納入一個命名空間,這個命名空間的名字就是std。std 意思是“標準命名空間”。

但是這時已經有很多用老式 C++ 開發的程序了,它們的代碼中并沒有使用命名空間,直接修改原來的庫會帶來一個很嚴重的后果:程序員會因為不愿花費大量時間修改老式代碼而極力反抗,拒絕使用新標準的 C++ 代碼。

C++ 開發人員想了一個好辦法,保留原來的庫和頭文件,它們在 C++ 中可以繼續使用,然后再把原來的庫復制一份,在此基礎上稍加修改,把類、函數、宏等納入命名空間 std 下,就成了新版 C++ 標準庫。這樣共存在了兩份功能相似的庫,使用了老式 C++ 的程序可以繼續使用原來的庫,新開發的程序可以使用新版的 C++ 庫。

為了避免頭文件重名,新版 C++ 庫也對頭文件的命名做了調整,去掉了后綴.h,所以老式 C++ 的iostream.h變成了iostreamfstream.h變成了fstream。而對于原來C語言的頭文件,也采用同樣的方法,但在每個名字前還要添加一個c字母,所以C語言的stdio.h變成了cstdiostdlib.h變成了cstdlib

需要注意的是,舊的 C++ 頭文件是官方所反對使用的,已明確提出不再支持,但舊的C頭文件仍然可以使用,以保持對C的兼容性。實際上,編譯器開發商不會停止對客戶現有軟件提供支持,可以預計,舊的 C++ 頭文件在未來數年內還是會被支持。

下面是我總結的 C++ 頭文件的現狀:
1) 舊的 C++ 頭文件,如 iostream.h、fstream.h 等將會繼續被支持,盡管它們不在官方標準中。這些頭文件的內容不在命名空間 std 中。

2) 新的 C++ 頭文件,如 iostream、fstream 等包含的基本功能和對應的舊版頭文件相似,但頭文件的內容在命名空間 std 中。

注意:在標準化的過程中,庫中有些部分的細節被修改了,所以舊的頭文件和新的頭文件不一定完全對應。

3) 標準C頭文件如 stdio.h、stdlib.h 等繼續被支持。頭文件的內容不在 std 中。

4) 具有C庫功能的新C++頭文件具有如 cstdio、cstdlib 這樣的名字。它們提供的內容和相應的舊的C頭文件相同,只是內容在 std 中。

可以發現,對于不帶.h的頭文件,所有的符號都位于命名空間 std 中,使用時需要聲明命名空間 std;對于帶.h的頭文件,沒有使用任何命名空間,所有符號都位于全局作用域。這也是 C++ 標準所規定的。

使用C++的頭文件

雖然 C++ 幾乎完全兼容C語言,C語言的頭文件在 C++ 中依然被支持,但 C++ 新增的庫更加強大和靈活,請讀者盡量使用這些 C++ 新增的頭文件,例如 iostream、fstream、string 等。

前面幾節我們使用了C語言的格式輸出函數 printf,引入了C語言的頭文件 stdio.h,將C代碼和 C++ 代碼混合在了一起,我不推薦這樣做,請盡量使用 C++ 的方式。下面的例子演示了如何使用 C++ 庫進行輸入輸出:

#include <iostream>
#include <string>int main(){//聲明命名空間stdusing namespace std;//定義字符串變量string str;//定義 int 變量int age;//從控制臺獲取用戶輸入cin>>str>>age;//將數據輸出到控制臺cout<<str<<"已經成立"<<age<<"年了!"<<endl;return 0;
}

在 main() 函數中聲明命名空間 std,它的作用范圍就位于 main() 函數內部,如果在其他函數中又用到了 std,就需要重新聲明,請看下面的例子:

#include <iostream>void func(){//必須重新聲明using namespace std;cout<<"http://c.biancheng.net"<<endl;
}int main(){//聲明命名空間stdusing namespace std;cout<<"C語言"<<endl;func();return 0;
}

如果希望在所有函數中都使用命名空間 std,可以將它聲明在全局范圍中,例如:

#include <iostream>//聲明命名空間std
using namespace std;void func(){cout<<"http://c.biancheng.net"<<endl;
}int main(){cout<<"C語言"<<endl;func();return 0;
}

很多教程中都是這樣做的,將 std 直接聲明在所有函數外部,這樣雖然使用方便,但在中大型項目開發中是不被推薦的,這樣做增加了命名沖突的風險,我推薦在函數內部聲明 std。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/444080.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/444080.shtml
英文地址,請注明出處:http://en.pswp.cn/news/444080.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++ new和delete

在C語言中&#xff0c;動態分配內存用 malloc() 函數&#xff0c;釋放內存用 free() 函數。如下所示&#xff1a; int *p (int*) malloc( sizeof(int) * 10 ); //分配10個int型的內存空間free(p); //釋放內存 在cpp中&#xff0c;這兩個函數仍然可以使用&#xff0c;但是C又…

Java 的內存管理機制是怎樣的?

Java 的內存管理機制是怎樣的&#xff1f;

leetcode1103. 分糖果 II 該模擬就模擬,別老想著優化

排排坐&#xff0c;分糖果。 我們買了一些糖果 candies&#xff0c;打算把它們分給排好隊的 n num_people 個小朋友。 給第一個小朋友 1 顆糖果&#xff0c;第二個小朋友 2 顆&#xff0c;依此類推&#xff0c;直到給最后一個小朋友 n 顆糖果。 然后&#xff0c;我們再回到…

leetcode912. 排序數組 有范圍的排序統統用桶排序

給你一個整數數組 nums&#xff0c;請你將該數組升序排列。 示例 1&#xff1a; 輸入&#xff1a;nums [5,2,3,1] 輸出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 輸入&#xff1a;nums [5,1,1,2,0,0] 輸出&#xff1a;[0,0,1,1,2,5] 提示&#xff1a; 1 < nums.len…

隊列【數據結構】

注意 我們的銷毀隊列是否能夠成功取決申請空間的方式&#xff0c;動態申請出來的空間都是可以進行銷毀的&#xff0c;對于靜態的話是不能直接進行銷毀的 ADT 相當于是c當中的類結構&#xff0c;是處理數據時&#xff0c;提前對數據進行一定的管理操作&#xff0c;就是將某一件事…

C++繼承詳解

廢話不多說直接上代碼 class 派生類名:&#xff3b;繼承方式&#xff3d; 基類名{ 派生類新增加的成員 }; 繼承方式限定了基類成員在派生類中的訪問權限&#xff0c;包括 public&#xff08;公有的&#xff09;、private&#xff08;私有的&#xff09;和 protected&…

串【數據結構F】

先來講解一下串結構的概念性質的東西&#xff0c;以及我們需要注意的一些問題 串結構簡單的ADT以及一些基本的操作 最小操作函數&#xff1a;就是功能已經達到了最小的功能實現了&#xff0c;不能繼續執行更大的功能&#xff0c;類似于我們在家蓋房子一樣&#xff0c;水泥的…

C++ STL與迭代器

將容器類模板實例化時&#xff0c;會指明容器中存放的元素是什么類型的&#xff1a;可以存放基本類型的變量&#xff0c;也可以存放對象。 對象或基本類型的變量被插入容器中時&#xff0c;實際插入的是對象或變量的一個復制品。 STL 中的許多算法&#xff08;即函數模板&…

在JSP頁面中輸出JSON格式數據

JSON-taglib是一套使在JSP頁面中輸出JSON格式數據的標簽庫。 JSON-taglib主頁&#xff1a; http://json-taglib.sourceforge.net/index.html JAR包下載地址&#xff1a; http://sourceforge.net/projects/json-taglib/files/latest/download 使用方法&#xff1a; 1、下載js…

git/github使用完整教程(1)基礎

安裝git 在Linux上安裝Git 首先輸入git&#xff0c;看看系統有沒有安裝Git&#xff1a; $ git The program git is currently not installed. You can install it by typing: sudo apt-get install git像上面的命令&#xff0c;有很多Linux會友好地告訴你Git沒有安裝&#x…

git/github使用完整教程(2)分支

分支 首先&#xff0c;我們創建dev分支&#xff0c;然后切換到dev分支&#xff1a; $ git checkout -b dev Switched to a new branch devgit checkout命令加上-b參數表示創建并切換&#xff0c;相當于以下兩條命令&#xff1a; $ git branch dev $ git checkout dev Switch…

數組【數據結構】

前提 數組的定義以及數組的延伸 這種不好進行理解&#xff0c;那么我們下面以二維數組進行解釋 多維數組的數據特點 存儲數組結構的兩種方式 問題抽象總結

Kafka深度解析

原創文章&#xff0c;轉載請務必將下面這段話置于文章開頭處&#xff08;保留超鏈接&#xff09;。 本文轉發自技術世界&#xff0c;原文鏈接 http://www.jasongj.com/2015/01/02/Kafka深度解析 背景介紹 Kafka簡介 Kafka是一種分布式的&#xff0c;基于發布/訂閱的消息系統。…

數據的存儲特殊矩陣壓縮存儲【數據結構F】

以行為主序 以列為主序 矩陣的前提分類 三角矩陣