??作者:日出等日落
??專欄:C++
不要去等誰(shuí),所有的不期而遇都在路上。
?
前言?
C++是在C的基礎(chǔ)之上,容納進(jìn)去了面向?qū)ο缶幊趟枷耄⒃黾恿嗽S多有用的庫(kù),以及編程范式等。熟悉C語(yǔ)言之后,對(duì)C++學(xué)習(xí)有一定的幫助
本章節(jié)主要目標(biāo):
1. 補(bǔ)充C語(yǔ)言語(yǔ)法的不足,以及C++是如何對(duì)C語(yǔ)言設(shè)計(jì)不合理的地方進(jìn)行優(yōu)化的,比如:作用 域方面、IO方面、函數(shù)方面、指針?lè)矫?、宏方面等?
2. 為后續(xù)類和對(duì)象學(xué)習(xí)打基礎(chǔ)。
C++關(guān)鍵字??
C++總計(jì)63個(gè)關(guān)鍵字,C語(yǔ)言32個(gè)關(guān)鍵字
ps:下面我們只是看一下C++有多少關(guān)鍵字,不對(duì)關(guān)鍵字進(jìn)行具體的講解。后面我們學(xué)到以后再 細(xì)講。
?
命名空間?
在C/C++中,變量、函數(shù)和后面要學(xué)到的類都是大量存在的,這些變量、函數(shù)和類的名稱將都存在于全局作用域中,可能會(huì)導(dǎo)致很多沖突。使用命名空間的目的是對(duì)標(biāo)識(shí)符的名稱進(jìn)行本地化, 以避免命名沖突或名字污染,namespace關(guān)鍵字的出現(xiàn)就是針對(duì)這種問(wèn)題的。
#include <stdio.h>
#include <stdlib.h>
int rand = 10;
// C語(yǔ)言沒(méi)辦法解決類似這樣的命名沖突問(wèn)題,所以C++提出了namespace來(lái)解決
int main()
{
printf("%d\n", rand);
return 0;
}
局部變量和全局變量
C語(yǔ)言中,局部變量?jī)?yōu)先于全局變量
int a = 10;
void fun1()
{
int a = 1;
printf("%d\n", a);//運(yùn)行結(jié)果為1
}
?在有局部變量的情況下,如何使用全局變量
在全局變量前面加::(域作用限定符)
int a = 10;
void fun1()
{
int a = 1;
printf("%d\n", a);//運(yùn)行結(jié)果為1
printf("%d\n", ::a);//運(yùn)行結(jié)果為10
}
命名空間定義
定義命名空間,需要使用到namespace關(guān)鍵字,后面跟命名空間的名字,然后接一對(duì){}即可,{} 中即為命名空間的成員。
命名空間(namespace)——命名空間域,只影響使用,不影響生命周期
c++當(dāng)變量重命名的時(shí)候,但都不能被改變量名時(shí),就需要命名空間
命名空間可以嵌套,甚至可以多次嵌套
變量放在命名空間內(nèi)
// bit是命名空間的名字,一般開(kāi)發(fā)中是用項(xiàng)目名字做命名空間名。
// 1. 正常的命名空間定義
namespace bit
{
// 命名空間中可以定義變量/函數(shù)/類型
int rand = 10;
int Add(int left, int right)
{
return left + right;
}
struct Node
{
struct Node* next;
int val;
};
}
//2. 命名空間可以嵌套
// 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;
}
}
}
//3. 同一個(gè)工程中允許存在多個(gè)相同名稱的命名空間,編譯器最后會(huì)合成同一個(gè)命名空間中。
// ps:一個(gè)工程中的test.h和上面test.cpp中兩個(gè)N1會(huì)被合并成一個(gè)
// test.h
namespace N1
{
int Mul(int left, int right)
{
return left * right;
}
}
?
- 注意:一個(gè)命名空間就定義了一個(gè)新的作用域,命名空間中的所有內(nèi)容都局限于該命名空間中
- 當(dāng)變量不是放在命名空間時(shí),變量默認(rèn)在局部和全局找。
- 當(dāng)變量放在命名空間時(shí),變量默認(rèn)先去命名空間找,然后再去局部和全局找。
?命名空間使用
namespace bit
{
// 命名空間中可以定義變量/函數(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;
}
命名空間的使用有三種方式:
- 加命名空間名稱及作用域限定符
int main() { printf("%d\n", N::a); return 0; }
- 使用using將命名空間中某個(gè)成員引入
using N::b; int main() { printf("%d\n", N::a); printf("%d\n", b); return 0; }
- 使用using namespace 命名空間名稱 引入
using namespce N; int main() { printf("%d\n", N::a); printf("%d\n", b); Add(10, 20); return 0; }
C++輸入&輸出
#include<iostream>
// std是C++標(biāo)準(zhǔn)庫(kù)的命名空間名,C++將標(biāo)準(zhǔn)庫(kù)的定義實(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)算符。
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í),所以我們這里只是簡(jiǎn)單學(xué)習(xí)他們的使用。后面我們?cè)诟钊氲膶W(xué)習(xí)IO流用法及原理。
#include <iostream>
using namespace std;
int main()
{
int a;
double b;
char c;
// 可以自動(dòng)識(shí)別變量的類型
cin>>a;
cin>>b>>c;
cout<<a<<endl;
cout<<b<<" "<<c<<endl;
return 0;
}
?std命名空間的使用慣例:
std是C++標(biāo)準(zhǔn)庫(kù)的命名空間,如何展開(kāi)std使用更合理呢?
1. 在日常練習(xí)中,建議直接using namespace std即可,這樣就很方便。
2. using namespace std展開(kāi),標(biāo)準(zhǔn)庫(kù)就全部暴露出來(lái)了,如果我們定義跟庫(kù)重名的類型/對(duì) 象/函數(shù),就存在沖突問(wèn)題。該問(wèn)題在日常練習(xí)中很少出現(xiàn),但是項(xiàng)目開(kāi)發(fā)中代碼較多、規(guī)模 大,就很容易出現(xiàn)。所以建議在項(xiàng)目開(kāi)發(fā)中使用,像std::cout這樣使用時(shí)指定命名空間 + using std::cout展開(kāi)常用的庫(kù)對(duì)象/類型等方式。
缺省參數(shù)
缺省參數(shù)概念
缺省參數(shù)是聲明或定義函數(shù)時(shí)為函數(shù)的參數(shù)指定一個(gè)缺省值。在調(diào)用該函數(shù)時(shí),如果沒(méi)有指定實(shí) 參則采用該形參的缺省值,否則使用指定的實(shí)參。
有缺省參數(shù)時(shí):
- 當(dāng)函數(shù)調(diào)用的時(shí)候,有傳函數(shù)參數(shù)時(shí),就用傳過(guò)來(lái)的函數(shù)參數(shù),沒(méi)有傳函數(shù)參數(shù)就用缺省參數(shù)的值
void Func(int a = 0) { cout<<a<<endl; } int main() { Func(); // 沒(méi)有傳參時(shí),使用參數(shù)的默認(rèn)值 輸出0 Func(10); // 傳參時(shí),使用指定的實(shí)參 輸出10 return 0; }
缺省參數(shù)分類?
- 全缺省參數(shù)
void Func(int a = 10, int b = 20, int c = 30)
{
cout<<"a = "<<a<<endl;
cout<<"b = "<<b<<endl;
cout<<"c = "<<c<<endl;
}
- 半缺省參數(shù)
void Func(int a, int b = 10, int c = 20)
{
cout<<"a = "<<a<<endl;
cout<<"b = "<<b<<endl;
cout<<"c = "<<c<<endl;
}
注意:
1. 半缺省參數(shù)必須從右往左依次來(lái)給出,不能間隔著給
2. 缺省參數(shù)不能在函數(shù)聲明和定義中同時(shí)出現(xiàn)
3. 在有缺省參數(shù)的情況下,只能不給有缺省參數(shù)的函數(shù)參數(shù)傳值,沒(méi)有缺省參數(shù)的函數(shù)必須傳值?
4. 聲明和定義缺省參數(shù)不能在函數(shù)聲明和定義中同時(shí)出現(xiàn)
函數(shù)重載
函數(shù)重載概念
函數(shù)重載:是函數(shù)的一種特殊情況,C++允許在同一作用域中聲明幾個(gè)功能類似的同名函數(shù),這 些同名函數(shù)的形參列表(參數(shù)個(gè)數(shù) 或 類型 或 類型順序)不同,常用來(lái)處理實(shí)現(xiàn)功能類似數(shù)據(jù)類型 不同的問(wèn)題
1.函數(shù)名和返回類型相同
2.參數(shù)個(gè)數(shù) 或 類型 或 類型順序有一種或者多種不同
#include<iostream>
using namespace std;
// 1、參數(shù)類型不同
int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}
double Add(double left, double right)
{
cout << "double Add(double left, double right)" << endl;
return left + right;
}
// 2、參數(shù)個(gè)數(shù)不同
void f()
{
cout << "f()" << endl;
}
void f(int a)
{
cout << "f(int a)" << endl;
}
// 3、參數(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;
}
int main()
{
Add(10, 20);
Add(10.1, 20.2);
f();
f(10);
f(10, 'a');
f('a', 10);
return 0;
}
引用?
引用概念
引用不是新定義一個(gè)變量,而是給已存在變量取了一個(gè)別名,編譯器不會(huì)為引用變量開(kāi)辟內(nèi)存空 間,它和它引用的變量共用同一塊內(nèi)存空間。
引用操作符(&)
引用不是新定義一個(gè)變量,而是給已存在變量取了一個(gè)別名
類型& 引用變量名(對(duì)象名) = 引用實(shí)體;?
void TestRef()
{
int a = 10;
int& ra = a;//<====定義引用類型
printf("%p\n", &a);
printf("%p\n", &ra);
}
?注意:引用類型必須和引用實(shí)體是同種類型的
引用特性?
1. 引用在定義時(shí)必須初始化
2. 一個(gè)變量可以有多個(gè)引用
3. 引用一旦引用一個(gè)實(shí)體,再不能引用其他實(shí)體
void TestRef()
{
int a = 10;
// int& ra; // 該條語(yǔ)句編譯時(shí)會(huì)出錯(cuò)
int& ra = a;
int& rra = a;
printf("%p %p %p\n", &a, &ra, &rra);
}
指針和引用的區(qū)別
在語(yǔ)法概念上引用就是一個(gè)別名,沒(méi)有獨(dú)立空間,和其引用實(shí)體共用同一塊空間。
int main()
{
int a = 10;
int& ra = a;
cout<<"&a = "<<&a<<endl;
cout<<"&ra = "<<&ra<<endl;
return 0;
}
?在底層實(shí)現(xiàn)上實(shí)際是有空間的,因?yàn)橐檬前凑罩羔樂(lè)绞絹?lái)實(shí)現(xiàn)的。
int main()
{
int a = 10;
int& ra = a;
ra = 20;
int* pa = &a;
*pa = 20;
return 0;
}
?
引用和指針的不同點(diǎn):
1. 引用概念上定義一個(gè)變量的別名,指針存儲(chǔ)一個(gè)變量地址。
2. 引用在定義時(shí)必須初始化,指針沒(méi)有要求
3. 引用在初始化時(shí)引用一個(gè)實(shí)體后,就不能再引用其他實(shí)體,而指針可以在任何時(shí)候指向任何 一個(gè)同類型實(shí)體
4. 沒(méi)有NULL引用,但有NULL指針
5. 在sizeof中含義不同:引用結(jié)果為引用類型的大小,但指針始終是地址空間所占字節(jié)個(gè)數(shù)(32 位平臺(tái)下占4個(gè)字節(jié))
6. 引用自加即引用的實(shí)體增加1,指針自加即指針向后偏移一個(gè)類型的大小
7. 有多級(jí)指針,但是沒(méi)有多級(jí)引用
8. 訪問(wèn)實(shí)體方式不同,指針需要顯式解引用,引用編譯器自己處理
9. 引用比指針使用起來(lái)相對(duì)更安全
內(nèi)聯(lián)函數(shù)?
概念?
以inline修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù),編譯時(shí)C++編譯器會(huì)在調(diào)用內(nèi)聯(lián)函數(shù)的地方展開(kāi),沒(méi)有函數(shù)調(diào)用建立棧幀的開(kāi)銷,內(nèi)聯(lián)函數(shù)提升程序運(yùn)行的效率。相對(duì)比宏
宏的缺點(diǎn):
1.不能調(diào)試
2.沒(méi)有類型安全的檢查
3.有些場(chǎng)景下非常復(fù)雜
inline int Add(int x, int y)
{
int z = x + y;
return z;
}
int main()
{
int ret = Add(1, 2);
cout << ret << endl;
return 0;
}
inline是一種以空間換時(shí)間的做法,如果編譯器將函數(shù)當(dāng)成內(nèi)聯(lián)函數(shù)處理,在編譯階段,會(huì) 用函數(shù)體替換函數(shù)調(diào)用,缺陷:可能會(huì)使目標(biāo)文件變大,優(yōu)勢(shì):少了調(diào)用開(kāi)銷,提高程序運(yùn) 行效率。
auto關(guān)鍵字
使用auto定義變量時(shí)必須對(duì)其進(jìn)行初始化,在編譯階段編譯器需要根據(jù)初始化表達(dá)式來(lái)推導(dǎo)auto 的實(shí)際類型。因此auto并非是一種“類型”的聲明,而是一個(gè)類型聲明時(shí)的“占位符”,編譯器在編 譯期會(huì)將auto替換為變量實(shí)際的類型。
用auto聲明指針類型時(shí),用auto和auto*沒(méi)有任何區(qū)別,但用auto聲明引用類型時(shí)則必須 加&?
#include <iostream>
using namespace std;
int main()
{
int a = 0;
auto b = a;
auto c = &a;
//typeid(變量名).name()可以獲取變量的實(shí)際類型
cout << typeid(b).name() << endl;//int
cout << typeid(c).name() << endl;//int*
return 0;
}
當(dāng)在同一行聲明多個(gè)變量時(shí),這些變量必須是相同的類型,否則編譯器將會(huì)報(bào)錯(cuò),因?yàn)榫幾g 器實(shí)際只對(duì)第一個(gè)類型進(jìn)行推導(dǎo),然后用推導(dǎo)出來(lái)的類型定義其他變量
?
void TestAuto()
{
auto a = 1, b = 2;
auto c = 3, d = 4.0; // 該行代碼會(huì)編譯失敗,因?yàn)閏和d的初始化表達(dá)式類型不同
}
注意:
- auto不能作為函數(shù)的參數(shù)
- auto不能直接用來(lái)聲明數(shù)組
范圍for?
對(duì)于一個(gè)有范圍的集合而言,由程序員來(lái)說(shuō)明循環(huán)的范圍是多余的,有時(shí)候還會(huì)容易犯錯(cuò)誤。因 此C++11中引入了基于范圍的for循環(huán)。for循環(huán)后的括號(hào)由冒號(hào)“ :”分為兩部分:第一部分是范 圍內(nèi)用于迭代的變量,第二部分則表示被迭代的范圍。?
int array[] = { 1,2,3,4,5,6,6,4 };
for (int i = 0; i < sizeof(array) / sizeof(int); i++)
{
cout << array[i] << " ";
}
cout << endl;
//范圍for --語(yǔ)法糖
for (auto e : array)
{
cout << e << " ";
}//兩種結(jié)果一樣
cout << endl;
?
自動(dòng)依次取數(shù)組中數(shù)據(jù)賦值給e對(duì)象,自動(dòng)判斷結(jié)束
for循環(huán)后的括號(hào)由冒號(hào)“ :”分為兩部分:
第一部分是范圍內(nèi)用于迭代的變量,第二部分則表示被迭代的范圍。
指針空值nullptr
void fun(int)
{
cout << "f(int)" << endl;
}
void fun(int*)
{
cout << "f(int*)" << endl;
}
//C++中,NULL被定義為0,這也不知道為什么是個(gè)錯(cuò)誤不太好
int main()
{
f(0);
f(NULL);
return 0;
}
注意:
NULL實(shí)際是一個(gè)宏,在傳統(tǒng)的C頭文件(stddef.h)中文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-449321.html
在使用nullptr表示指針空值時(shí),不需要包含頭文件,因?yàn)閚ullptr是C++11作為新關(guān)鍵字引入的。
在C++11中,sizeof(nullptr) 與 sizeof((void*)0)所占的字節(jié)數(shù)相同。
為了提高代碼的健壯性,在后續(xù)表示指針空值時(shí)建議最好使用nullptr。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-449321.html
到了這里,關(guān)于【C++】C++入門知識(shí)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!