一文帶你初識(shí)C++和命名空間
1. 初識(shí)C++
C語言是結(jié)構(gòu)化和模塊化的語言,適合處理較小規(guī)模的程序。對(duì)于復(fù)雜的問題,規(guī)模較大的程序,需要高度的抽象和建模時(shí),C語言則不合適。為了解決軟件危機(jī), 20世紀(jì)80年代, 計(jì)算機(jī)界提出了OOP(objectoriented programming:面向?qū)ο?思想,支持面向?qū)ο蟮某绦蛟O(shè)計(jì)語言應(yīng)運(yùn)而生。所以我們經(jīng)常說到C++是面向?qū)ο蟮恼Z言,而C語言是面向過程的語言。
1982年,Bjarne Stroustrup博士在C語言的基礎(chǔ)上引入并擴(kuò)充了面向?qū)ο蟮母拍?,發(fā)明了一種新的程序語言。為了表達(dá)該語言與C語言的淵源關(guān)系,命名為C++。因此:C++是基于C語言而產(chǎn)生的,它既可以進(jìn)行C語言的過程化程序設(shè)計(jì),又可以進(jìn)行以抽象數(shù)據(jù)類型為特點(diǎn)的基于對(duì)象的程序設(shè)計(jì),還可以進(jìn)行面向?qū)ο蟮某绦蛟O(shè)計(jì)。
請大家記住C++誕生的時(shí)間(1982年)以及發(fā)明C++的大佬 —— “本賈尼”!
2. C++的發(fā)展階段
作為了解就好,但是也要知道我們現(xiàn)在是在用C++版本是多少。
階段 | 內(nèi)容 |
---|---|
C with classes | 類及派生類、公有和私有成員、類的構(gòu)造和析構(gòu)、友元、內(nèi)聯(lián)函數(shù)、賦值運(yùn)算符重載等 |
C++1.0 | 添加虛函數(shù)概念,函數(shù)和運(yùn)算符重載,引用、常量等 |
C++2.0 | 更加完善支持面向?qū)ο?,新增保護(hù)成員、多重繼承、對(duì)象的初始化、抽象類、靜態(tài)成員以及const成員函數(shù) |
C++3.0 | 進(jìn)一步完善,引入模板,解決多重繼承產(chǎn)生的二義性問題和相應(yīng)構(gòu)造和析構(gòu)的處理 |
C++98 | C++標(biāo)準(zhǔn)第一個(gè)版本,絕大多數(shù)編譯器都支持,得到了國際標(biāo)準(zhǔn)化組織(ISO)和美國標(biāo)準(zhǔn)化協(xié)會(huì)認(rèn)可,以模板方式重寫C++標(biāo)準(zhǔn)庫,引入了STL(標(biāo)準(zhǔn)模板庫) |
C++03 | C++標(biāo)準(zhǔn)第二個(gè)版本,語言特性無大改變,主要:修訂錯(cuò)誤、減少多異性 |
C++05 | C++標(biāo)準(zhǔn)委員會(huì)發(fā)布了一份計(jì)數(shù)報(bào)告(Technical Report,TR1),正式更名C++0x,即:計(jì)劃在本世紀(jì)第一個(gè)10年的某個(gè)時(shí)間發(fā)布 |
C++11 | 增加了許多特性,使得C++更像一種新語言,比如:正則表達(dá)式、基于范圍for循環(huán)、auto關(guān)鍵字、新容器、列表初始化、標(biāo)準(zhǔn)線程庫等 |
C++14 | 對(duì)C++11的擴(kuò)展,主要是修復(fù)C++11中漏洞以及改進(jìn),比如:泛型的lambda表達(dá)式,auto的返回值類型推導(dǎo),二進(jìn)制字面常量等 |
C++17 | 在C++11上做了一些小幅改進(jìn),增加了19個(gè)新特性,比如:static_assert()的文本信息可選,F(xiàn)old表達(dá)式用于可變的模板,if和switch語句中的初始化器等 |
C++20 | 自C++11以來最大的發(fā)行版,引入了許多新的特性,比如:模塊(Modules)、協(xié)程(Coroutines)、范圍(Ranges)、概念(Constraints)等重大特性,還有對(duì)已有特性的更新:比如Lambda支持模板、范圍for支持初始化等 |
C++23 | 明確的對(duì)象參數(shù)(Deducing this)、if consteval、多維下標(biāo)運(yùn)算符、內(nèi)建衰減復(fù)制支持、標(biāo)記不可達(dá)代碼(std::unreachable)、平臺(tái)無關(guān)的假設(shè)([[assume]])、命名通用字符轉(zhuǎn)義、擴(kuò)展基于范圍的 for 循環(huán)中臨時(shí)變量的生命周期、constexpr 增強(qiáng)、簡化的隱式移動(dòng)、靜態(tài)運(yùn)算符 static operator[] 以及類模板參數(shù)推導(dǎo) |
C++還在不斷地向后發(fā)展。但是現(xiàn)在公司主流的是用的還是C++98和C++11,等大家以后工作時(shí)可以慢慢鉆研C++的新特性,現(xiàn)在這需要我們熟練的掌握C++98和C++11這兩個(gè)標(biāo)準(zhǔn)即可。
我們現(xiàn)在學(xué)習(xí)階段大都接觸到的也就是這兩種標(biāo)準(zhǔn)(C++11和C++98)。
2. 命名空間
2.1 為什么要有命名空間?
請大家看一下下面的代碼:
#include<stdio.h> int rand = 0; int main() { int rand = 10; printf("%d\n",rand); return 0; }
上面的代碼會(huì)不會(huì)報(bào)錯(cuò)?相信掌握C語言語法的讀者就會(huì)說,上面的代碼是可以正常編譯通過的。沒錯(cuò),上面的代碼的確是沒有任何問題的。
那如果我將上述的代碼做了一點(diǎn)改變,代碼還能正常編譯過去嗎?
#include<stdio.h> #include<stdlib.h> int rand = 0; int main() { int rand = 10; printf("%d\n",rand); return 0; }
如果你們自己去測試的話,顯然會(huì)出現(xiàn)編譯錯(cuò)誤。
這是什么原因呢?
編譯器說rand重定義,而且錯(cuò)誤是我們在引用stdlib.h的頭文件之后才出現(xiàn)的。到這里我們就意識(shí)到了有個(gè)rand的變量名或者時(shí)函數(shù)名,而我們知道一個(gè).c/.cpp的源文件在編譯階段的預(yù)處理階段會(huì)把頭文件的內(nèi)容給展開,所以就會(huì)出現(xiàn)rand重定義了。
這個(gè)問題在C語言上只能是要你改變這個(gè)變量名了。C++就能夠解決這個(gè)問題,即使你不更改變量名,編譯器也不會(huì)報(bào)錯(cuò),這個(gè)C++的利器就是命名空間
為了讓大家對(duì)命名空間的這個(gè)新事物引起更高的重視,我來給大家舉個(gè)生活中實(shí)際例子:
比如現(xiàn)在有一個(gè)互聯(lián)網(wǎng)公司,這個(gè)公司最近準(zhǔn)備研發(fā)一個(gè)項(xiàng)目,老板就把項(xiàng)目就分配給了一個(gè)小組,而小組里面有兩人小明和小剛負(fù)責(zé)分別負(fù)責(zé)這個(gè)項(xiàng)目的兩個(gè)模塊。他們兩個(gè)寫啊寫啊,終于有一天他們倆將各自寫的項(xiàng)目都提交了上去,編譯一下卻出現(xiàn)錯(cuò)誤,經(jīng)過檢查發(fā)現(xiàn)他們兩個(gè)項(xiàng)目的變量名有很多是重疊了,這個(gè)會(huì)出現(xiàn)命名沖突的問題。如果他們是用C語言來寫的話,那必定有一方得是改變變量命名,那兩個(gè)人肯定都不愿意改的。如果用C++的命名空間的話,就可以完美避開這個(gè)問題了。
好了,在講完命名空間的重要性之后,我們就得認(rèn)識(shí)一下命名空間的用法以及底層的原理!
2.2 命名空間的語法
namespace 命名空間名 { 內(nèi)容 }
下面我來一遍做展示,一遍拓展:
- 這個(gè)是我們進(jìn)行正常的命名空間定義:
namespace test { int rand = 10; int Add(int x, int y) { return x+y; } struct Node { int data; struct Node* next; } }
??我們不僅可以在命名空間定義并初始化變量,還可以進(jìn)行對(duì)函數(shù)的定義,結(jié)構(gòu)體的定義等。
- 命名空間可以嵌套:
namespace N1 { int a; int b; int Add(int left, int right) { return left + right; } namespace N2 { int c; int d; int Sub(int left, int right) { return left - right; } } }
??可以看到我們中命名空間去嵌套另一個(gè)命名空間。
- 同一個(gè)工程中允許不同的文件出現(xiàn)名稱相同的命名空間,但是最后編譯器會(huì)將不同文件相同名稱的命名空間給合并到一起:
//這個(gè)是test.h文件里面的命名空間 namespace N1 { int Mul(int left, int right) { return left * right; } } //這個(gè)是test.cpp文件里面的命名空間 namespace N1 { int a; int b; int Add(int left, int right) { return left + right; } namespace N2 { int c; int d; int Sub(int left, int right) { return left - right; } } }
經(jīng)過編譯器的編譯之后,最后的合并的結(jié)果就是:
namespace N1 { int Mul(int left, int right) { return left * right; } int a; int b; int Add(int left, int right) { return left + right; } namespace N2 { int c; int d; int Sub(int left, int right) { return left - right; } } }
2.3 命名空間的原理
提到命名空間,我們就不得不提另一個(gè)概念"域"。
想必大家或多或少都會(huì)在C語言中聽過"作用域"(全局域、局部域)這個(gè)名詞。這個(gè)就是"域"中的一種,在C++中還有命名空間域、類域等等。而我們現(xiàn)在說講的命名空間,它的實(shí)質(zhì)就是一種命名空間域。
那可能有的讀者會(huì)問,"域"是個(gè)什么東西?
那我們可以先從我們熟悉的入手,全局域和局部域。我們都知道在給全局變量和局部變量去相同的變量名時(shí),程序是不會(huì)報(bào)錯(cuò)的,這個(gè)就是"域"的作用。我們可以把"域"想象成一面墻,被這面的墻隔開的事物互不干擾,你干你的事,我剛我的事。
講到這里,我相信你已經(jīng)對(duì)命名空間域已經(jīng)有感覺了。我們也可以把命名空間域看作是一面墻,將局部域與全局域給隔開了。在這個(gè)域里面有自己獨(dú)自維護(hù)的變量。
??所以我們可以總結(jié)一下:命名空間是解決全局變量與頭文件的命名沖突問題,或者是解決同一個(gè)工程項(xiàng)目中不同模塊之間的命名沖突問題。
2.4 使用命名空間的三種方式
我們講解了命名空間的原理,那命名空間里面的成員我們該怎么引用呢?比如:
namespace test { // 命名空間中可以定義變量/函數(shù)/類型 int a = 0; int b = 1; int Add(int left, int right) { return left + right; } struct Node { struct Node* next; int val; }; }
int main() { // 編譯報(bào)錯(cuò):error C2065: “a”: 未聲明的標(biāo)識(shí)符 printf("%d\n", a); return 0; }
2.4.1 加命名空間名稱及作用域限定符( :: )
int main() { printf("%d\n", test::a); return 0; }
2.4.2 使用using關(guān)鍵字將命名空間中某個(gè)成員 引入
using test::b; int main() { printf("%d\n", test::a); printf("%d\n", b); return 0; }
這種方式建議使用?。?!
2.4.3 使用using namespace 命名空間名 引入
using namespace test; int main() { printf("%d\n", test::a); printf("%d\n", b); Add(10,20); return 0; }
??注意:使用這個(gè)方法時(shí)是有風(fēng)險(xiǎn)的(這個(gè)命名空間里面有著和全局變量一樣的變量名),所以我們在平時(shí)進(jìn)行練習(xí)或比賽的時(shí)候使用即可。
3. 簡單了解C++的輸入和輸出
我們再學(xué)一門新的語言時(shí),往往會(huì)都會(huì)干一件事,就是在屏幕上輸出"Hello World"。
所以這里我們就簡單認(rèn)識(shí)一下C++的輸入和輸出。
#include<iostream> // std是C++標(biāo)準(zhǔn)庫的命名空間名,C++將標(biāo)準(zhǔn)庫的定義實(shí)現(xiàn)都放到這個(gè)命名空間中 using namespace std; int main() { cout<<"Hello world!!!"<<endl; return 0; }
說明:
1. 使用cout標(biāo)準(zhǔn)輸出對(duì)象(控制臺(tái))和cin標(biāo)準(zhǔn)輸入對(duì)象(鍵盤)時(shí),必須包含< iostream >頭文件以及按命名空間使用方法使用std。
2. cout和cin是全局的流對(duì)象,endl是特殊的C++符號(hào),表示換行輸出,他們都包含在包含< iostream >頭文件中。
3. <<是流插入運(yùn)算符,>>是流提取運(yùn)算符。
4. 使用C++輸入輸出更方便,不需要像printf/scanf輸入輸出時(shí)那樣,需要手動(dòng)控制格式。
C++的輸入輸出可以自動(dòng)識(shí)別變量類型。
5. 實(shí)際上cout和cin分別是ostream和istream類型的對(duì)象,>>和<<也涉及運(yùn)算符重載等知識(shí),這些知識(shí)我們我們后續(xù)才會(huì)學(xué)習(xí),所以我們這里只是簡單學(xué)習(xí)他們的使用。
注意:早期標(biāo)準(zhǔn)庫將所有功能在全局域中實(shí)現(xiàn),聲明在.h后綴的頭文件中,使用時(shí)只需包含對(duì)應(yīng)頭文件即可,后來將其實(shí)現(xiàn)在std命名空間下,為了和C頭文件區(qū)分,也為了正確使用命名空間,規(guī)定C++頭文件不帶.h;舊編譯器(vc 6.0)中還支持<iostream.h>格式,后續(xù)編譯器已不支持,因此推薦使用+std的方式。
#include <iostream> using namespace std; int main() { int a = 10; double b = 3.1415; char c = 'l'; // 可以自動(dòng)識(shí)別變量的類型 cin>>a; cin>>b>>c; cout<<a<<endl; cout<<b<<" "<<c<<endl; return 0; }
??最后在聲明一點(diǎn),std命名空間的使用慣例:
std是C++標(biāo)準(zhǔn)庫的命名空間,如何展開std使用更合理呢?在日常練習(xí)中,建議直接using namespace std即可,這樣就很方便。
using namespace std展開,標(biāo)準(zhǔn)庫就全部暴露出來了,如果我們定義跟庫重名的類型/對(duì)象/函數(shù),就存在沖突問題。該問題在日常練習(xí)中很少出現(xiàn),但是項(xiàng)目開發(fā)中代碼較多、規(guī)模大,就很容易出現(xiàn)。所以建議在項(xiàng)目開發(fā)中使用,像std::cout這樣使用時(shí)指定命名空間 + using std::cout展開常用的庫對(duì)象/類型等方式。
總結(jié)
到此這篇關(guān)于C++和命名空間的文章就介紹到這了,更多相關(guān)C++和命名空間內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VisualStudio2022下配置 OpenMP多線程編程環(huán)境與運(yùn)行
本文主要介紹了VisualStudio2022下配置 OpenMP多線程編程環(huán)境與運(yùn)行,文中通過圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-06-06C語言帶你學(xué)會(huì)位段相關(guān)知識(shí)
這篇文章主要介紹了什么是位段,位段的聲明和結(jié)構(gòu)是類似的,位段的成員必須是 int、unsigned int 或signed int;位段的成員名后邊有一個(gè)冒號(hào)和一個(gè)數(shù)字,本文有詳細(xì)的代碼案例,感興趣的同學(xué)可以參考閱讀2023-04-04C語言中判斷素?cái)?shù)(求素?cái)?shù))的思路與方法實(shí)例
計(jì)算機(jī)或者相關(guān)專業(yè)基本上大一新生開始學(xué)編程都會(huì)接觸的一個(gè)問題就是判斷質(zhì)數(shù),下面這篇文章主要給大家介紹了關(guān)于C語言中判斷素?cái)?shù)(求素?cái)?shù))的思路與方法,需要的朋友可以參考下2022-03-03C語言實(shí)現(xiàn)手寫Map(全功能)的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用C語言實(shí)現(xiàn)手寫Map(全功能),文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C語言有一定幫助,需要的可以參考一下2022-08-08