本文章主要內容為C++對于C語言基礎語法方面,有哪些改進與提升,
目錄
- 1. 命名空間 namespace
- 1.1 概念
- 1.2 命名空間的定義
- 1.3 命名空間的使用
- 2. C++中強大的輸入與輸出
- 2.1 標準輸入輸出的使用
- 3. 方便的預設引數
- 3.1 概念
- 3.2 分類
- 4. 函式多載
- 4.1 概念
- 4.2 舉例
- 4.3 函式多載的呼叫原理
- 4.4 預設函式有函式多載嗎?
- 5. 參考(重點)
- 5.1 概念
- 5.2 如何使用
- 5.3 特性
- 5.4 常參考
- 5.5 使用場景
- 5.5.1 變數別名
- 5.5.2 做函式引數
- 5.5.3 做函式的回傳值使用
- 5.5.4 C/C++幾種傳值的效率對比
- 5.5.5 指標和參考的區別
- 6. 行內函式
- 6.1 概念
- 6.2 特性
- 6.3 宏函式和行內函式的區別
- 7. auto關鍵字
- 7.1 概念
- 7.2 使用方法
- 7.2.1 auto和指標/參考 聯合使用
- 7.2.2 在同一行宣告多個變數
- 7.3 auto關鍵字不能使用的場景
- 8. 范圍for回圈
- 8.1 概念
- 8.2 使用
- 總結

1. 命名空間 namespace
1.1 概念
??在程式撰寫時存在著大量的變數、函式、類等等,如果將這些內容放在全域作用域,難免會出現很多沖突,所以在C++中引入了命名空間這個概念,
??在命名空間中對識別符號進行名稱本地化,避免識別符號名稱沖突,
1.2 命名空間的定義
在命名空間中,可以定義函式,變數等等,
1.定義普通的命名空間
namespace A
{
int a = 10;
int b = 20;
int sum(int a, int b)
{
return a + b;
}
}
2.嵌套定義命名空間
namespce B
{
int c = 30;
namespace C
{
int a = 10;
struct STU
{
int id;
char name[16];
}
}
}
3.定義同名命名空間
同名的命名空間,編譯器會將兩個命名空間合成為一個空間,前提是兩個空間中不能存在同名的變數或函式,
namespace A
{
int c = 30;
int max(int a, int b)
{
return a > b ? a : b;
}
}
1.3 命名空間的使用
1.常規的使用方式 通過 ::域運算子訪問
int main()
{
cout << A::a << " " << A::b << endl;
cout << A::sum(1, 2);
// 使用嵌套命名空間
cout << B::C::a << endl;
return 0;
}
觀察發現如果多次使用這個作用域中的變數,每次都要這么寫,很麻煩,所以引入了第二種寫法,
2.使用using將命名空間中的成員引入
using A::a;
int main()
{
cout << a << B::c << endl;
int d = a;
int f = B::C;
return 0;
}
如果要大量使用當前命名空間中的元素,上面那種方法還是麻煩,所以直接引入命名空間,
3.將命名空間直接引入
using namespace A;
int main()
{
cout << a << endl;
cout << b << endl;
cout << sum(1, 2) << endl;
return 0;
}
2. C++中強大的輸入與輸出
??在C語言中,我們使用的輸入輸出是printf()和scanf(),在使用時,一不小心,就會錯誤的使用,不僅要注意型別、注意取地址符有沒有加,很麻煩,
??所以在C++中,引入了新的輸入輸出 cout 和 cin,
在使用輸入輸出時,必須包含
#include <iostream>這個頭檔案,以及標準的命名空間using namespace std;
2.1 標準輸入輸出的使用
#include <iostream>
using namespace std;
int main()
{
int a;
double b;
char c;
cin >> a;
cin >> b >> c;
cout << a << b << endl;
cout << c << " " << endl;
return 0;
}
3. 方便的預設引數
3.1 概念
??什么時預設引數,當我們在宣告或者定義函式時,給函式的引數指定一個默認值,這就是預設引數,呼叫函式時,如果沒有對函式中傳遞實參,則該函式就會默認使用預設引數,
3.2 分類
1.全預設引數 (全部引數都有默認值)
int add(int a = 1, int b = 2, int c = 3)
{
return a + b + c;
}
2.半預設引數 (只有部分引數有默認值,但必須從右向左依次給出)
void displyFun(int a, int b = 1, int c = 2)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
注意預設引數不能在函式宣告和定義中同時出現,如果在宣告和定義中同時給出預設值,編譯器則不知道對哪個值進行處理,
4. 函式多載
4.1 概念
??什么時函式多載,在我們的中文中,有時會出現一個詞有多種意思的情況,那么函式多載意義相同,
??在同一個作用域中,函式的名字相同,引數串列不同,這樣的函式叫做函式多載,
??引數串列不同分為:引數的個數不同,引數的型別不同,引數型別的順序不同,
注意:函式回傳值不同不構成多載
4.2 舉例
以下函式就構成了函式的多載,
int add(int x, int y)
{
return x + y;
}
double add(double x, double y)
{
return x + y;
}
long add(long x, long y)
{
return x + y;
}
int main()
{
add(1, 2);
add(1.0, 2.0)
add(2, 3);
}
4.3 函式多載的呼叫原理
??在編譯階段,編譯器會對函式的型別進行實參推演,根據推演的結果選擇合適的函式呼叫,如果有則進行呼叫,如果沒有合適的函式,編譯器會先對型別進行隱式轉換,如果轉換后有合適型別的函式則呼叫,如果沒有則會報錯,
關于函式多載實作的原理和函式多載為什么在C++中有,會在接下來的文章中介紹到,
4.4 預設函式有函式多載嗎?
void Test(int a = 10)
{
cout << TestDefault() << endl;
}
void Test(int a)
{
cout << Test() << endl;
}
??以上兩個函式,雖然滿足了函式定義,但在呼叫時產生了二義性,所以并不會發生函式多載,如果不傳遞引數,則系統就無法判定應該呼叫哪個函式,
5. 參考(重點)
5.1 概念
C語言的傳參方式:值傳遞 和 址傳遞
址傳遞:在使用時有些麻煩,并且可能會因為空指標的問題出現例外
值傳遞:雖然安全且使用方便,但在函式中無法通過形參改變實參
??C++中為了解決上述問題,引入了參考這一概念,
??參考不是去定義一個變數,而是對已經存在的變數起了一個別名,參考與共用一塊記憶體空間,并且可以通過參考值直接修改物體,
5.2 如何使用
語法格式型別& 參考變數名 = 參考物體
int main()
{
int a = 10;
int& ra = a; // 定義參考型別
ra = 20; // 對 a 的值也進行了修改
return 0;
}
5.3 特性
- 在定義時,必須要進行初始化,不初始化就會報錯
- 參考型別必須與參考的物體型別完全一致
- 一個變數可以有多個參考,但一個參考只能參考一個物體
- 物體的宣告周期長于參考
- 不能對常量進行參考
int& ra = 100; // err
const int& ra = 100 // ok注意這種方式,不是和常量使用一塊地址空間,而是新開辟了一塊空間存盤100
5.4 常參考
??對參考加上const修飾符就是常參考,常參考則不能通過參考去修改物體,
void testFun()
{
double d = 12.34;
const int& rd = d; // ok
// 這個操作竟然成功了!!!
// rd是誰的參考?
d = 32.34;
cout << rd << endl; // 值沒有變化
}
上述程式中,我們需要明白rd到底是誰的參考,修改物體后,參考值沒有變化,所以rd不是d的參考,在參考時,double和int進行了隱式轉換生成了一個臨時變數,rd參考的是該臨時變數,但是不知道該臨時變數的名字,也不知道該臨時變數的空間地址,所以該臨時變數具有常性,
5.5 使用場景
5.5.1 變數別名
簡化代碼,對名字較長的變數取別名,方便使用
5.5.2 做函式引數
做為函式引數,相當于地址傳遞,不僅安全而且使用方便,
void Swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
int main()
{
int a = 10;
int b = 20;
Swap(a, b);
cout << a << b << endl;
return 0;
}
5.5.3 做函式的回傳值使用
注意:不要這樣使用
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);
Add(3, 4);
cout << "Add(1, 2) = " << ret << endl; // 列印結果為 7
return 0;
}
上述代碼列印結果為 7,按照我們的認知,列印結果應該為3,但為什么為7,
因為函式在呼叫時會建立堆疊幀,呼叫完后會將堆疊幀銷毀,但是這個函式的回傳值是個參考,回傳值會保存堆疊環境中的值,所以第一次保存了1+2的結果,緊接著又呼叫了Add(3, 4),有在相同的位置建立了堆疊幀,并且參考使用的地址還是該地址,所以又保存了3+4的值,
當參考作為函式回傳值時,不要回傳函式堆疊上的空間,可以回傳不受函式銷毀而影響的值:全域變數、靜態變數、參考引數
5.5.4 C/C++幾種傳值的效率對比
直接看結論,效率對比 傳值 < 傳址 = 傳參考
1.傳值:每次傳值操作,都相當于將引數值拷貝依次,如果是一個結構體成員并且結構體成員中資料量較大時,則會將引數中的資料一個一個拷貝,效率會很低
2.傳址:傳遞首地址,速度快
3.傳參考:同樣傳地址速度快
傳參考與傳地址效率相同,當時參考簡化了寫法,并且使用更簡單,
5.5.5 指標和參考的區別
相同點
- 傳遞效率基本相同
- 在傳參時都可以到達同樣的效果,修改形參改變外部實參
- 在底層的實作方式相同,參考在語法概念上就是一個別名,沒有獨立空間和物體共用一塊記憶體空間,在底層的實作方式和指標相同,(即參考在底層實際上也有空間,該空間中實際放置的時其所參考的物體)
不同點
- 參考在定義時必須初始化,指標沒有要求
- 參考在初始化階段參考一個物體就不能在參考其它物體,指標可以隨意改變指向,
因為int& -> int* const- 沒有NULL參考,但是又NULL指標
- 在sizeof中的含義不同,sizeof(參考) = 物體型別大小,sizeof(指標) = 地址空間大小,
- 參考自增、物體也自增,指標自增則向后移動一位
- 有多級指標,但沒有多級參考
- 訪問物體的方式不同
- 參考使用比指標安全,指標可能為空,但參考不能,
6. 行內函式
6.1 概念
??行內函式實際上就是C語言中的宏函式,以inline修飾的函式叫做行內函式,編譯時編譯器會在呼叫行內函式的地方展開,省去了函式壓堆疊是的開銷,以此來提升效率,
inline int sum(int a, int b)
{
return a + b;
}
6.2 特性
- 以空間換取時間,省去函式額外的呼叫開銷,所以當代碼很長或者函式中含有回圈遞回的函式不適合作為行內函式
- inline對于編譯器只是一種建議,編譯器會自動優化,如果內斂函式體中有回圈遞回等操作西,編譯器會忽略行內,
- inline不建議將宣告與定義分離,分離后會導致鏈接錯誤,因為inline函式被展開后,就不會有函式地址,而是整塊替換,鏈接時就找不到該函式,
6.3 宏函式和行內函式的區別
- 宏函式本身沒有型別,引數也沒有型別,在使用時不會進行型別檢查,但行內函式就是函式依舊可以進行除錯,與引數的檢查,
- 宏函式展開后無法進行代碼除錯,行內函式可以,
7. auto關鍵字
7.1 概念
??C語言中的auto的關鍵字含義為,使用auto修飾的變數,是具有自動存盤器的區域變數,
??C++中的auto關鍵字,不再是一個存盤型別的指示符,而是作為一個新的型別指示符,根據初始化值,自動確定該變數的型別,在編譯器編譯時推導而得,
void type()
{
auto a = 10;
auto b = 10.1;
auto c = 'c';
cout << typeid(a).name() << endl;
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
}
7.2 使用方法
7.2.1 auto和指標/參考 聯合使用
??用auto宣告指標型別是,用auto和auto*沒有任何區別,但用auto宣告參考型別是必須加&
void TestAuto()
{
int a = 10;
auto ra = &a; //相當與對a取地址
auto* b = &a;
auto& c = a; // 參考a
cout << typeid(a).name() << endl;
cout << typeid(ra).name() << endl;
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
}
7.2.2 在同一行宣告多個變數
??在同一行多個變數時,這些變數型別必須相同,否則編譯器會報錯,因為編譯器只會對第一個型別進行推導,然后根據推導結果定義其他變數,
7.3 auto關鍵字不能使用的場景
1.auto不能作為函式的引數,因為編譯時無法確定引數型別
2.auto不能用來宣告陣列
8. 范圍for回圈
8.1 概念
??對于一個有范圍的集合而言,由程式員來定義范圍是多余的,所以C++引入了基于范圍的for回圈,
for(迭代變數 : 迭代范圍)
8.2 使用
void TestFor()
{
int arr[] = { 1, 2, 3, 4, 5, 6 };
for (auto& e : arr)
{
e *= 2;
}
for (auto e : arr)
{
cout << e << " ";
}
}
總結
以上的全部內容就是C++相對于C語言中的一些新特性了,因為這篇文章是面向入門的,所以內容沒有那么深入,其中的函式多載涉及到了編譯器層面所以沒有詳細解釋,在接下來的文章會進行說明,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/286806.html
標籤:其他
