C++超詳細梳理基礎知識
命名空間的使用
來源
在瞭解命名空間的原理和使用之前,我們先要理解,命名空間是為瞭解決什麼問題。
C++是在C的基礎上發展而形成的一種語言,完全兼容C的語法,也加入瞭許多新的規則和語法來解決C的缺陷。
命名空間就是為瞭解決C語言中的重復命名的問題。
首先我們來看看這麼一個代碼:
#include<stdio.h> int main() { int scanf = 20; printf("%d", scanf); return 0; }
我們都知道scanf在C之中是一個函數名,但詭異的是我們在主函數中聲明scanf是有效的並且輸出結果是20.
在這個程序內的scanf就是表示是一個int型整數,這是根據就近原則或者說是局部優先原則確定的。
接下來我們看看另一個程序:
#include<stdio.h> int main() { int scanf = 20; scanf("%d", &scanf); printf("%d", scanf); return 0; }
在我們想要scanf作為函數使用時出現瞭問題,兩者之間命名沖突。
在C語言中我們被告誡不要讓變量名與函數名沖突,但是在C++中有沒有合適的解決方法呢?
命名空間的使用
我們先來書寫一個在C++中最為簡單的程序:
#include<iostream> using namespace std; int main() { cout << "hello world" << endl; return 0; }
這裡我們就看到瞭namespace命名空間,但是現在它是用來幹什麼的我們還不清楚,首先我們先來瞭解一下它。
一個命名空間就定義瞭一個新的作用域,命名空間中的所有內容都局限於該命名空間中。
讓我們從代碼方面來看看命名空間到底是什麼:
#include<iostream> using namespace std; namespace N1 { int printf = 30; int strlen = 20; } int main() { cout << "hello world" << endl; cout << N1::printf << endl; return 0; }
我們聲明瞭一個命名空間N1,在內部聲明瞭兩個int類型的變量,通過作用域限定符::我們就可以調用命名空間中的變量。
並且命名空間中也可以嵌套命名空間:
namespace N1 { int printf = 30; int strlen = 20; namespace N2 { int a = 0; } }
通過上面的解釋,我們明白瞭,命名空間適用於將聲明的名稱之間相互隔離,防止命名沖突。比如說,我們調用N1::printf時,::將范圍限定在N1這個命名空間之中,而不會與函數名printf沖突,反之亦然。
那麼一開始我們看到的那個程序是什麼意思呢?
我們先來看另一個版本的程序:
int main() { std::cout << "hello world" << std::endl; //cout << N1::printf << endl; return 0; }
顯然std也是一個命名空間,通過作用域限定符調用命名空間std內的內容。
那麼一開始的
using namespace std;
是用來幹嘛的呢?
using的作用是把命名空間中的內容在全局空間中展開,命名空間中的變量就成為瞭全局變量,調用時就不需要命名空間名加上作用域限定符瞭。
實際上命名空間有三種使用方式,各有優劣。
不展開
也就是
std::cout << "hello world" << std::endl;
的方式,要使用命名空間中的名稱,就要使用::來限定命名空間,完全避免瞭沖突,在大工程中使用。缺點就是在日常練習中書寫代碼較為繁瑣。
部分展開
使用using將命名空間中成員引入,將一些我們常用的符號在全局中展開,就可以大大簡化代碼,是在第一個方法和第三個方法之間取一個折中。
using std::cout; using std::endl; int main() { cout << "hello world" << endl; //cout << N1::printf << endl; return 0; }
全展開
使用using namespace 命名空間名稱引入:
using namespace std; int main() { cout << "hello world" << endl; //cout << N1::printf << endl; return 0; }
這個方法是有問題的,相當於一夜回到解放前。好不容易搞個命名空間隔離瞭,結果一行代碼全給展開瞭,直接在全局空間聲明,完全沒有防止命名沖突的作用,隻在日常練習中使用。
函數重載
函數重載的規則
自然語言中,一個詞可以有多重含義,人們可以通過上下文來判斷該詞真實的含義,即該詞被重載瞭。
比如:以前有一個笑話,國有兩個體育項目大傢根本不用看,也不用擔心。一個是乒乓球,一個是男足。前者是“誰也贏不瞭!”,後者是“誰也贏不瞭!”
函數重載是函數的一種特殊情況,C++允許在同一作用域中聲明幾個功能類似的同名函數,這些同名函數的形參列表(參數 個數 或 類型 或 順序)必須不同,常用來處理實現功能類似數據類型不同的問題。
比如下面的相加函數:
int Add(int left, int right) { return left+right; } double Add(double left, double right) { return left+right; } long Add(long left, long right) { return left+right; } int main() { Add(10, 20); Add(10.0, 20.0); Add(10L, 20L); return 0; }
雖然函數名相同,但是所帶參數的類型不同,所以在調用的時候能夠調用不同的函數定義,讓函數的使用更加靈活。
這裡要特別註意的是函數重載的規則:同名函數的形參列表(參數 個數 或 類型 或 順序)必須不同。
short Add(short left, short right) { return left+right; } int Add(short left, short right) { return left+right; }
那麼兩個同名函數,算不算是函數重載呢,顯然他們的形式參數的個數 ,類型以及 順序都是一樣的,隻是返回類型不同,不構成重載函數。
C++如何實現函數重載
我們都知道C是沒有函數重載這個功能的,那麼C++是怎麼實現的呢?
其實是通過C++的函數名修飾來實現函數重載的。
大傢這裡可能有一些迷糊,這需要我們對代碼的編譯過程有一定的瞭解:
C和C++的區別在於,在編譯的符號匯總中,C語言是使用函數的原名進行匯總的,導致瞭一個名稱隻能對應一個函數,所以不能進行函數重載。
但是在C++中,符號匯總起來的是經過修飾的函數名,即使原名稱一樣,由於參數 個數 或 類型 或 順序不同,經過修飾後的符號名也不同,比如說:
int Add(int left, int right) { return left+right; } double Add(double left, double right) { return left+right; } long Add(long left, long right) { return left+right; }
比如說這三個函數經過函數名修飾之後就變成瞭——Addii、Adddd、Addll。於是我們在後續的使用中就可以很好地區分這三個函數瞭,即使在我們看來這三個函數名是一樣的,但是在計算機看來這三個完全就是三個不一樣的函數。
引用
引用可以說就是給變量取別名。是怎麼實現的呢?
#include<iostream> int main() { int a = 0; int b = 0; int& c = a; c = 10; return 0; }
其中 int& c = a; 就是把c作為a的別名,這時c和a指向的內存空間是同一塊。
當改變c的值時,a中的值同時改變。
但是,在使用過程中也有一些需要註意的事項——
1.引用類型必須和引用實體是同種類型的
2.引用在定義時必須初始化
int a; int& b = a;
3.一個變量可以有多個引用
int a = 0; int& b = a; int& c = a; int$ d = c;
4.引用一旦引用一個實體,再不能引用其他實體
#include<iostream> int main() { int a = 0; int b = 0; int& c = a; int& c = b; c = 10; return 0; }
到此這篇關於C++超詳細梳理基礎知識的文章就介紹到這瞭,更多相關C++基礎內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!