免費(fèi)英文建設(shè)網(wǎng)站企點(diǎn)qq官網(wǎng)
目錄
1. C++關(guān)鍵字
2. 命名空間
1)命名空間的引入和概述
2)命名空間的定義
3)std與命名空間的使用
4).相關(guān)特性
3. C++輸入&輸出
4. 缺省參數(shù)
1 )缺省參數(shù)概念
2)使用及分類
a.全缺省
b.部分缺省
5. 函數(shù)重載
1)?函數(shù)重載概念
2)分類
3)原理
6. 引用
1)引用概念和使用
2)引用特性
3)常引用
4)使用場(chǎng)景
5)引用與指針
7. 內(nèi)聯(lián)函數(shù)
1)概念
2)特性
8. auto關(guān)鍵字(C++11)
1)概念和使用
2)特性
9. 基于范圍的for循環(huán)(C++11)
1 )范圍for的語法
2) 范圍for的使用條件
10. 指針空值---nullptr(C++11)
1)NULL
2)nullptr
?
1. C++關(guān)鍵字
C++總計(jì)63個(gè)關(guān)鍵字,C語言32個(gè)關(guān)鍵字
asm | do | if | return | try | continue |
auto | double | inline | short | typedef | for |
bool | dynamic_cast | int | signed | typeid | public |
break | else | long | sizeof | typename | throw |
case | enum | mutable | static | union | wchar_t |
catch | explicit | namespace | static_cast | unsigned | default |
char | export | new | struct | using | friend |
class | extern | operator | switch | virtual | register |
const | false | private | template | void | true |
const_cast | float | protected | this | volatile | while |
delete | goto | reinterpret_cast |
2. 命名空間
1)命名空間的引入和概述
在c++中,符號(hào)常量、變量、函數(shù)、結(jié)構(gòu)、枚舉、類和對(duì)象等名稱將都存在于全局作用域中,用戶的命名與這些名稱相同而沖突的可能性非常大。并且工程越大,互相沖突性的可能性越大。另外使用標(biāo)準(zhǔn)類庫時(shí),也可能導(dǎo)致命名沖突。為了避免這些情況,C++引入了關(guān)鍵字namespace(命名空間/名字空間/名稱空間)來控制標(biāo)識(shí)符的作用域從而達(dá)到目的。
例如,在c里面:
int a=1;
void f1()
{int a=2;//可以取名相同,因?yàn)橛虿煌?}
void f2()
{int a=3;
}
2)命名空間的定義
定義命名空間,需要使用到namespace關(guān)鍵字,后面加命名空間的名字,然后接一對(duì){}即可,{}
中即為命名空間的成員。
//分別定義名字為A,B的命名空間
namespace A {int a = 10;void print(){cout << "A:print" << endl;}
}
namespace B {int a = 20;void print(){cout << "A:print" << endl;}
}
void test1()
{cout << "A中a = " << A::a << endl;cout << "B中a = " << B::a << endl;
}
int main()
{test1();A::print();B::print();
}
編譯器默認(rèn)只在全局域里查找相關(guān)變量函數(shù)等,不會(huì)進(jìn)入特定的命名空間里查找。一個(gè)命名空間就定義了一個(gè)新的作用域,命名空間中的所有內(nèi)容都局限于該命名空間中。需要使用特定的命名空間里的變量等,需要指定命名空間,指定命名空間需要使用"::"。
"::"是作用域限定符或者稱作用域運(yùn)算符(scope operator),
用法:namespace::name
3)std與命名空間的使用
std命名空間是C++中標(biāo)準(zhǔn)庫類型對(duì)象的命名空間。如需要使用cout等就有多種方法。
a.??using namespce std;? -->代表把整體std展開,此時(shí)應(yīng)該避免與sd里的名稱沖突。
? ? ?編譯器此時(shí)會(huì)去std里面查找相關(guān)內(nèi)容。
b.??所有使用都用"::"指定。?
?c.??只把部分常用的展開,已經(jīng)展開的不需要用"::"。
4).相關(guān)特性
a.?命名空間只能全局范圍內(nèi)定義
b. 命名空間可以嵌套
namespace A
{int a = 0;namespace B{int a = 100;}
}
?c. 隨時(shí)把新的成員加入已有的命名空間中
namespace A
{int a = 0;}
namespace A
{int b = 100;
}
int main()
{cout << A::a << endl << A::b << endl;
}
?所以當(dāng)項(xiàng)目里面有兩個(gè)命名空間相同時(shí),會(huì)被合并。
d. 命名空間中的函數(shù)可以在“命名空間”外定義
namespace A
{int a = 0;void A_fun();}
void A::A_fun()
{cout << " hello " << endl;
}
int main()
{A::A_fun();
}
3. C++輸入&輸出
#include<iostream>
using namespace std;
int main()
{int d;cin >> d;cout << d << endl;
}
1)在C++里, 如果需要使用輸入輸出時(shí),必須包含< iostream >頭文件,它包含了用于輸入輸出的對(duì)象, cout和cin是全局的流對(duì)象,cin
表示標(biāo)準(zhǔn)輸入、cout
表示標(biāo)準(zhǔn)輸出。endl是特殊的C++符號(hào),表示換行輸出。
2)?<<是流插入運(yùn)算符,>>是流提取運(yùn)算符。
3)使用C++輸入輸出不需要手動(dòng)控制格式,自動(dòng)識(shí)別變量類型。
4)?實(shí)際上cout和cin分別是ostream和istream類型的對(duì)象,>>和<<是運(yùn)算符重載。
注:早期標(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ù)編譯器已不支持,因
此推薦使用<iostream>+std的方式。
4. 缺省參數(shù)
1 )缺省參數(shù)概念
聲明或定義函數(shù)時(shí)為函數(shù)的參數(shù)指定一個(gè)缺省值。在調(diào)用該函數(shù)時(shí),如果沒有指定實(shí)參則采用該形參的缺省值,否則使用指定的實(shí)參。
?
void fun1(int a = 100)
{cout << "a的值:" << a << endl;
}
int main()
{fun1();fun1(1);fun1(5);}
2)使用及分類
a.全缺省
void fun(int a = 1, int b = 2, int c = 2)
{cout << a << b << c << endl;
}int main()
{fun();fun(12);fun(10,20);
}
b.部分缺省
void fun(int a , int b = 2, int c = 2)
{cout << a << b << c << endl;
}
int main()
{fun(12);fun(10,20);fun(10, 20, 30);//fun(10, , 30);
}
注意:
!缺省參數(shù)不能在函數(shù)聲明和定義中同時(shí)出現(xiàn),一般都在聲明中給出。
!缺省值必須是常量或者全局變量
5. 函數(shù)重載
1)?函數(shù)重載概念
在開發(fā)中,有時(shí)候我們可能需要實(shí)現(xiàn)幾個(gè)功能類似的函數(shù),只是有些細(xì)節(jié)不同。例如希望交換兩個(gè)變量的值,兩個(gè)變量有多種類型,可以是 int、float、char、bool 等,在C語言中,只能分別設(shè)計(jì)出各個(gè)不同名的函數(shù)。
C++允許在同一作用域中聲明幾個(gè)功能類似的同名函數(shù),這些同名函數(shù)的形參列表(參數(shù)個(gè)數(shù) 或 類型 或 類型順序)不同,常用來處理實(shí)現(xiàn)功能類似數(shù)據(jù)類型不同的問題。
void swap(int* a, int* b)
{int ret = *a;*a = *b;*b = ret;
}
void swap(double* a, double* b)
{double ret = *a;*a = *b;*b = ret;
}
2)分類
a、參數(shù)類型不同
int Add(int left, int right)
{
return left + right;
}
double Add(double left, double right)
{
return left + right;
}
b、參數(shù)個(gè)數(shù)不同
void f()
{
cout << "f()" << endl;
}
void f(int a)
{
cout << "f()" << endl;
}
c、參數(shù)類型順序不同
void f(int a, char b)
{
cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
cout << "f(char b, int a)" << endl;
}
注意:函數(shù)的返回值不同時(shí)不能完成函數(shù)重載。?
3)原理
①為什么C語言不支持函數(shù)重載?
程序在預(yù)編譯階段會(huì)經(jīng)歷預(yù)處理、編譯、匯編和鏈接生成可執(zhí)行程序的過程。
首先在匯編過程中編譯器對(duì)每個(gè)文件都會(huì)收集全局符號(hào)并生成全局符號(hào)如果暫時(shí)找不到函數(shù)的地址(例如只有函數(shù)的聲明),符號(hào)表里將會(huì)填寫一個(gè)沒有意義的值:
生成了多個(gè)符號(hào)表后,在鏈接過程中要對(duì)符號(hào)表進(jìn)行合并。在合并的過程中如果函數(shù)出現(xiàn)了兩次,——函數(shù)有效的地址值就會(huì)作為Add函數(shù)最終的地址值。C語言中因?yàn)閮蓚€(gè)重名函數(shù)的地址都是有效值,在重定位,合并符號(hào)表的時(shí)候就會(huì)產(chǎn)生沖突和歧義。
?②C++為什么支持函數(shù)重載
C++會(huì)對(duì)寫入符號(hào)表的同名函數(shù)進(jìn)行名字修飾(name Mangling),這樣函數(shù)重載的函數(shù)的名字都不一樣,有效地址也不一樣,這樣合并符號(hào)表就不會(huì)發(fā)生沖突。
注:不同編譯器名字修飾的方法不同。 圖為舉例。
如果兩個(gè)函數(shù)函數(shù)名和參數(shù)是一樣的,返回值不同是不構(gòu)成重載的,因?yàn)榧词狗祷刂挡煌?#xff0c;修飾的函數(shù)不同解決了符號(hào)表合并時(shí)的函數(shù)名沖突,但是真正調(diào)用時(shí)只有實(shí)參無法確定使用哪個(gè)函數(shù)。?
6. 引用
1)引用概念和使用
引用變量是一個(gè)別名,把該引用初始化為某個(gè)變量x,就可以使用該引用名稱或變量名稱x來讀取或者修改x變量。此時(shí)兩者是同一個(gè)東西。
使用方法:引用類型必須和引用實(shí)體是同種類型的
類型& 引用變量名(對(duì)象名) = 引用實(shí)體;
int a=10;
int& a_othername=a;
2)引用特性
a. 引用在定義時(shí)必須初始化
b. 一個(gè)變量可以有多個(gè)引用
c. 引用一旦引用一個(gè)實(shí)體,再不能引用其他實(shí)體
void TestRef()
{
int a = 10;
// int& ra; // 該條語句編譯時(shí)會(huì)出錯(cuò)
int& ra = a;
int& rra = ra;
printf("%p %p %p\n", &a, &ra, &rra);
}
3)常引用
指針和引用賦值/初始化時(shí)權(quán)限只能縮小或者平移,但不能放大
?
const int a = 10;
//int& ra = a; // 該語句編譯時(shí)會(huì)出錯(cuò),a為常量,需要用const類型接收
const int& ra = a;// int& b = 10; // 該語句編譯時(shí)會(huì)出錯(cuò),b為常量,需要用const類型接收
const int& b = 10;double d = 12.34;
//int& rd = d; // 該語句編譯時(shí)會(huì)出錯(cuò),類型不同const int& rd = d; //隱式類型轉(zhuǎn)換/*
int i=1;
double d=i;
//隱式類型轉(zhuǎn)換
*/?
??
4)使用場(chǎng)景
a. 做參數(shù)
void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}
b. 做返回值
1)值返回
不管返回的值在棧,堆,靜態(tài)區(qū)的任何地方,值返回都會(huì)產(chǎn)生臨時(shí)變量。
2)引用返回
只要出了函數(shù)后該返回的值還存在,就可以通過引用返回,直接將返回值返回,省去臨時(shí)變量的傳遞。
?
int& Add(int a, int b)
{
int c = a + b;//錯(cuò)誤
return c;
}
int main()
{
int& ret = Add(1, 2);
Add(3, 4);
cout << "Add(1, 2) is :"<< ret <<endl;
return 0;
}?
當(dāng)返回一個(gè)引用時(shí),要注意被引用的對(duì)象不能超出作用域。所以返回一個(gè)對(duì)局部變量的引用是不合法的,但是,可以返回一個(gè)對(duì)靜態(tài)變量的引用。
傳值、傳引用效率比較
-以引用作為參數(shù),在傳參期間,函數(shù)會(huì)直接傳遞實(shí)參,而傳值需要多一份臨時(shí)的拷貝,因此用值作為參數(shù)效率是非常低下的,尤其是當(dāng)參數(shù)或者返回值類型非常大時(shí),效率就更低。
-返回引用實(shí)際返回的是一個(gè)指向返回值的隱式指針,在內(nèi)存中不會(huì)產(chǎn)生副本,是直接將返回值拷貝給接收變量,這樣就避免產(chǎn)生臨時(shí)變量,相比返回普通類型的執(zhí)行效率更高,而且這個(gè)返回引用的函數(shù)也可以作為賦值運(yùn)算符的左操作數(shù)
5)引用與指針
語法層面:引用就是一個(gè)別名,沒有獨(dú)立空間,和其引用實(shí)體共用同一塊空間
引用在底層實(shí)現(xiàn)上實(shí)際是有空間的,因?yàn)橐檬前凑罩羔樂绞絹韺?shí)現(xiàn)的。
引用和指針的不同點(diǎn):
1. 引用概念上定義一個(gè)變量的別名,指針存儲(chǔ)一個(gè)變量地址。
2. 引用在定義時(shí)必須初始化,指針沒有要求
3. 引用在初始化時(shí)引用一個(gè)實(shí)體后,就不能再引用其他實(shí)體,而指針可以在任何時(shí)候指向任何
一個(gè)同類型實(shí)體
4. 沒有NULL引用,但有NULL指針
5. 在sizeof中含義不同:引用結(jié)果為引用類型的大小,但指針始終是地址空間所占字節(jié)個(gè)數(shù)(32
位平臺(tái)下占4個(gè)字節(jié))
6. 引用自加即引用的實(shí)體增加1,指針自加即指針向后偏移一個(gè)類型的大小
7. 有多級(jí)指針,但是沒有多級(jí)引用
8. 訪問實(shí)體方式不同,指針需要顯式解引用,引用編譯器自己處理
9. 引用比指針使用起來相對(duì)更安全
7. 內(nèi)聯(lián)函數(shù)
在C語言里宏分為宏常量,宏函數(shù)。然而宏具有許多不安全的問題,且不易調(diào)試。c++里引入了內(nèi)聯(lián)函數(shù)代替宏函數(shù),一般提倡使用const和enum替代宏常量。
1)概念
以inline修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù)。
我們知道,一般情況下,所有函數(shù)調(diào)用時(shí)都需要建立棧幀和傳遞參數(shù)。
?如果在上述函數(shù)前增加inline關(guān)鍵字將其改成內(nèi)聯(lián)函數(shù),在編譯期間編譯器會(huì)把該函數(shù)的代碼副本放置在每個(gè)調(diào)用該函數(shù)的地方,用函數(shù)體替換函數(shù)的調(diào)用。不會(huì)產(chǎn)生建立棧幀和傳遞參數(shù)的消耗,提升程序運(yùn)行的效率。
2)特性
a.?inline是一種以空間(目標(biāo)文件的空間)換時(shí)間的做法,如果編譯器將函數(shù)當(dāng)成內(nèi)聯(lián)函數(shù)處理,在編譯階段,會(huì)
用函數(shù)體展開替換函數(shù)調(diào)用,缺陷:可能會(huì)使目標(biāo)文件體積變大,優(yōu)勢(shì):少了調(diào)用開銷,提高程序運(yùn)行效率。
b. inline對(duì)于編譯器而言只是一個(gè)建議,不同編譯器關(guān)于inline實(shí)現(xiàn)機(jī)制可能不同,一般建
議:將函數(shù)規(guī)模較小(即函數(shù)不是很長(zhǎng),具體沒有準(zhǔn)確的說法,取決于編譯器內(nèi)部實(shí)現(xiàn))、不
是遞歸、且頻繁調(diào)用的函數(shù)采用inline修飾,否則編譯器會(huì)忽略inline特性。
?c.inline不建議聲明和定義分離,分離會(huì)導(dǎo)致編譯時(shí)鏈接錯(cuò)誤。因?yàn)閕nline函數(shù)會(huì)被展開,沒有函數(shù)地址,不會(huì)進(jìn)入符號(hào)表,這樣進(jìn)行鏈接時(shí)會(huì)發(fā)生鏈接錯(cuò)誤,找不到函數(shù)定義。
// F.h
#include <iostream>
using namespace std;
inline void f(int i);
// F.cpp
#include "F.h"
void f(int i)
{
cout << i << endl;
}
// main.cpp
#include "F.h"
int main()
{
f(10);
return 0;
}
// 鏈接錯(cuò)誤:main.obj : error LNK2019: 無法解析的外部符號(hào) "void __cdecl
f(int)" (?f@@YAXH@Z),該符號(hào)在函數(shù) _main 中被引用
d.在類定義中的定義的函數(shù)都是內(nèi)聯(lián)函數(shù),即使沒有使用?inline?說明符。
8. auto關(guān)鍵字(C++11)
1)概念和使用
a.引入
隨著程序越來越復(fù)雜,程序中用到的類型也越來越復(fù)雜,像:
std::map<std::string, std::string>::iterator
這樣的類型太長(zhǎng)了,特別容易寫錯(cuò)。在C語言里可以通過typedef給類型取別名解決:
typedef std::map<std::string, std::string> Map;
int main()
{Map m{ { "apple", "蘋果" },{ "orange", "橙子" }, {"pear","梨"} };Map::iterator it = m.begin();while (it != m.end()){//....}return 0;
}
但是typedef還是存在一些問題:
b.概念
為了解決這個(gè)問題,并且在編程時(shí),常常需要把表達(dá)式的值賦值給變量,這就要求在聲明變量的時(shí)候清楚地知道表達(dá)式的類型。然而有時(shí)候要做到這點(diǎn)并非那么容易。因此C++11給auto賦予了新的含義。auto不再是一個(gè)存儲(chǔ)類型指示符,而是作為一個(gè)新的類型指示符來指示編譯器,auto聲明的變量必須由編譯器在編譯時(shí)期推導(dǎo)而得。
?
int a = 10;
auto b = a;
auto c = 'a';
auto d = fun();auto& ra=a;
auto* pa=&a;
auuto e;//error,報(bào)錯(cuò)?
【注意】
使用auto定義變量時(shí)必須對(duì)其進(jìn)行初始化,在編譯階段編譯器需要根據(jù)初始化表達(dá)式來推導(dǎo)auto
的實(shí)際類型。因此auto并非是一種“類型”的聲明,而是一個(gè)類型聲明時(shí)的“占位符”,編譯器在編
譯期會(huì)將auto替換為變量實(shí)際的類型。
2)特性
1. 用auto聲明指針類型時(shí),用auto和auto*沒有任何區(qū)別,但用auto聲明引用類型時(shí)則必須加&
2.?當(dāng)在同一行聲明多個(gè)變量時(shí),這些變量必須是相同的類型,否則編譯器將會(huì)報(bào)錯(cuò),因?yàn)榫幾g
器實(shí)際只對(duì)第一個(gè)類型進(jìn)行推導(dǎo),然后用推導(dǎo)出來的類型定義其他變量。
?c. auto不能作為函數(shù)的參數(shù)
// 此處代碼編譯失敗,auto不能作為形參類型,因?yàn)榫幾g器無法對(duì)a的實(shí)際類型進(jìn)行推導(dǎo)
void TestAuto(auto a)
{}
d. auto不能直接用來聲明數(shù)組
e.為了避免與C++98中的auto發(fā)生混淆,C++11只保留了auto作為類型指示符的用法
f.auto在實(shí)際中最常見的優(yōu)勢(shì)用法就是跟C++11提供的新式for循環(huán),和lambda表達(dá)式等進(jìn)行配合使用。
?
9. 基于范圍的for循環(huán)(C++11)
1 )范圍for的語法
在C++98中如果要遍歷一個(gè)數(shù)組,可以按照以下方式進(jìn)行:
void TestFor()
{
int array[] = { 1, 2, 3, 4, 5 };
for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
array[i] *= 2;
for (int* p = array; p < array + sizeof(array)/ sizeof(array[0]); ++p)
cout << *p << endl;
}
對(duì)于一個(gè)有范圍的集合而言,由程序員來說明循環(huán)的范圍是多余的,有時(shí)候還會(huì)容易犯錯(cuò)誤。因
此C++11中引入了基于范圍的for循環(huán)。for循環(huán)后的括號(hào)由冒號(hào)“ :”分為兩部分:第一部分是范
圍內(nèi)用于迭代的變量,第二部分則表示被迭代的范圍。
void TestFor()
{
int array[] = { 1, 2, 3, 4, 5 };
for(auto& e : array)
e *= 2;
for(auto e : array)
cout << e << " ";
return 0;
}
void TestFor(int array[])
{
for(auto& e : array)
cout<< e <<endl;
}
比
注意:與普通循環(huán)類似,可以用continue來結(jié)束本次循環(huán),也可以用break來跳出整個(gè)循環(huán)。
2) 范圍for的使用條件
a. for循環(huán)迭代的范圍必須是確定的
對(duì)于數(shù)組而言,就是數(shù)組中第一個(gè)元素和最后一個(gè)元素的范圍;對(duì)于類而言,應(yīng)該提供
begin和end的方法,begin和end就是for循環(huán)迭代的范圍。
注意:以下代碼就有問題,因?yàn)閒or的范圍不確定
void TestFor(int array[])
{
for(auto& e : array)
cout<< e <<endl;
}
//函數(shù)里,數(shù)組名array已經(jīng)退化成了指針
b. 迭代的對(duì)象要實(shí)現(xiàn)++和==的操作。
10. 指針空值---nullptr(C++11)
1)NULL
在良好的C/C++編程習(xí)慣中,聲明一個(gè)變量時(shí)最好給該變量一個(gè)合適的初始值,否則可能會(huì)出現(xiàn)
不可預(yù)料的錯(cuò)誤,比如未初始化的指針。如果一個(gè)指針沒有合法的指向,我們基本都是按照如下
方式對(duì)其進(jìn)行初始化:
int* p1 = NULL;
int* p2 = 0;
NULL實(shí)際是一個(gè)宏,在傳統(tǒng)的C頭文件(stddef.h)中,可以看到如下代碼:
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
可以看到,NULL可能被定義為字面常量0,或者被定義為無類型指針(void*)的常量。不論采取何
種定義,在使用空值的指針時(shí),都不可避免的會(huì)遇到一些麻煩,比如:
void f(int)
{
cout<<"f(int)"<<endl;
}
void f(int*)
{
cout<<"f(int*)"<<endl;
}
int main()
{
f(0);
f(NULL);
f((int*)NULL);
return 0;
}
程序本意是想通過f(NULL)調(diào)用指針版本的f(int*)函數(shù),但是由于NULL被定義成0,因此與程序的
初衷相悖。第二次調(diào)用時(shí)f會(huì)匹配到int參數(shù)那個(gè)。
2)nullptr
c++引入了nullptr完善NULL,其實(shí)質(zhì)是(void*)0
在C++98中,字面常量0既可以是一個(gè)整形數(shù)字,也可以是無類型的指針(void*)常量,但是編譯器
默認(rèn)情況下將其看成是一個(gè)整形常量,如果要將其按照指針方式來使用,必須對(duì)其進(jìn)行強(qiáng)轉(zhuǎn)(void
*)0。
注意:
1. 在使用nullptr表示指針空值時(shí),不需要包含頭文件,因?yàn)閚ullptr是C++11作為新關(guān)鍵字引入
的。
2.在C++11中,sizeof(nullptr) 與 sizeof((void*)0)所占的字節(jié)數(shù)相同。
3. 為了提高代碼的健壯性,在后續(xù)表示指針空值時(shí)建議最好使用nullptr。
?