怎樣免費(fèi)做網(wǎng)站搜索引擎排名影響因素有哪些
當(dāng)學(xué)習(xí)了C語(yǔ)言之后,很多的小伙伴都想進(jìn)一步學(xué)習(xí)C++,但兩者有相當(dāng)一部分的內(nèi)容都是重疊的,不知道該從哪些方面開(kāi)始入門(mén)C++,這篇文章羅列了從C到C++必學(xué)的入門(mén)知識(shí),學(xué)完就算是踏入C++的大門(mén)了。
1. 命名空間
寫(xiě)C的時(shí)候,偶爾可能不小心就和庫(kù)函數(shù)沖突了,又或者當(dāng)兩個(gè)程序員以相同的名字命名變量或函數(shù),就會(huì)發(fā)生沖突。C++就提出了一個(gè)很好的解決方案——命名空間。
命名空間的關(guān)鍵字是namespace,定義方式如下:
【定義方式】
namespace N1
{int a = 3;int b = 4;
?int Add(int x1, int x2){return x1 + x2;}
?struct Node{struct Node* next;int val;};
?namespace N2{int c = 0;int d = 0;}
}
從示例中可以看出,命名空間中可以包含變量、函數(shù)、類(lèi)型以及嵌套另一個(gè)命名空間
【使用方式】
1. 命名空間+作用域限定符
int main() {printf("%d\n", N1::a);return 0;
}
2. using將命名空間中某個(gè)成員引入
using N1::b;
int main() {printf("%d\n", N1::a);printf("%d\n", b);return 0;
}
3. using namespace 變量空間
using namespace N1;
int main() {printf("%d\n", a);printf("%d\n", b);return 0;
}
2. 輸入輸出
其實(shí)C語(yǔ)言的printf/scanf在C++中還可以使用,不過(guò)C++有獨(dú)有的輸入輸出方式,就是cin/cout
【使用說(shuō)明】
1. 必須包含iostream頭文件,注意是<iostream>
2. 需要使用命名空間std,因?yàn)閏in/cout在其中的(日常練習(xí)可以這么做,但做項(xiàng)目的時(shí)候最好使用 std::cin 的方式展開(kāi))
3. 使用時(shí)要用<<流插入操作符/>>流提取操作符,不知道是什么沒(méi)關(guān)系,看示例是怎么用的就行,cout用<<,cin用>> ?
4. 變量之間也是用<<或>>連接,如果需要換行用endl
【示例】
#include <iostream>
using namespace std;
?
int main()
{cout << "hello world!" << endl;return 0;
}
【解惑】
我們有了printf和scanf為什么還要學(xué)習(xí)cin和cout呢,因?yàn)槠淇梢?span style="background-color:#fefcd8;">自動(dòng)識(shí)別變量的類(lèi)型,相對(duì)來(lái)說(shuō)就方便了很多,不用考慮太多。不過(guò)cin/cout相對(duì)于前者慢一些,在大量數(shù)據(jù)需要輸入輸出時(shí)就會(huì)有較大的時(shí)間差距。
3. 缺省參數(shù)
聲明或者定義函數(shù)時(shí)為函數(shù)參數(shù)指定一個(gè)缺省值,當(dāng)函數(shù)沒(méi)有傳遞對(duì)應(yīng)的參數(shù)時(shí),就用缺省參數(shù)來(lái)代替(有點(diǎn)像備胎的感覺(jué)doge)
#include <iostream>
using namespace std;void Func (int a = 10)
{cout << a << endl;
}int main()
{Func(); //輸出10Func(100); //輸出100return 0;
}
【分類(lèi)】
全缺省參數(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;
}int main()
{Func(9, 8, 5);Func(9, 8);return 0;
}
半缺省參數(shù):只有部分參數(shù)給缺省值
void Func(int a, int b = 20, int c = 30)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl;
}//錯(cuò)誤寫(xiě)法
//void Func(int a = 10, int b, int c = 30)
//void Func(int a = 10, int b = 20, int c)
//void Func(int a = 10, int b, int c)int main()
{Func(9);Func(9, 8);Func(9, 8, 5);return 0;
}
注意:
1. 半缺省參數(shù)只能從右往左給,不能跳躍給,也是為了避免傳錯(cuò)參數(shù),出現(xiàn)歧義
2. 缺省參數(shù)不能同時(shí)在定義和聲明中出現(xiàn),一般在聲明中給
3. 缺省值必須是全局變量或常量
4.?函數(shù)重載
C++中允許在同一個(gè)作用域中出現(xiàn)參數(shù)列表不同(參數(shù)個(gè)數(shù)或類(lèi)型不同)的同名函數(shù),稱(chēng)這種現(xiàn)象為函數(shù)重載
【示例】
#include <iostream>
using namespace std;
?
//參數(shù)個(gè)數(shù)不同
void f1(int x, int y)
{cout << "void f1(int x, int y)" << endl;
}
?
void f1(int m)
{cout << "void f1(int m)" << endl;
}
?
//參數(shù)類(lèi)型不同
void f2(int m)
{cout << "void f2(int m)" << endl;
}
?
void f2(double m)
{cout << "void f2(double m)" << endl;
}
?
//參數(shù)類(lèi)型順序不同,本質(zhì)就是類(lèi)型不同
void f3(int x, double y)
{cout << "void f3(int x, double y)" << endl;
}
?
void f3(double x, int y)
{cout << "void f3(double x, int y)" << endl;
}
?
int main()
{f1(10, 20);f1(10);cout << endl;f2(10);f2(1.0);cout << endl;f3(10, 1.0);f3(1.0, 10);
?
?return 0;
}
【原理】
C++的編譯器會(huì)對(duì)函數(shù)進(jìn)行修飾,一種函數(shù)變量類(lèi)型對(duì)于一種編碼,所以不同的變量類(lèi)型或者個(gè)數(shù)對(duì)應(yīng)不同的匯編代碼,所以函數(shù)名相同并不影響其分別不同的函數(shù)。
而C語(yǔ)言中,相同的函數(shù)名是區(qū)分不開(kāi)的。
(此部分需要對(duì)程序的翻譯和執(zhí)行部分有一定的了解,可以暫時(shí)跳過(guò))
5. 引用
引用是對(duì)已經(jīng)創(chuàng)建的變量起別名,操作符是&
【示例】
#include <iostream>
using namespace std;int main()
{int a = 1;int& b = a;cout << a << endl;cout << b << endl;//打印結(jié)果都是1cout << &a << endl;cout << &b << endl;//打印出來(lái)是同一個(gè)地址,也就意味著在同一個(gè)空間return 0;
}
結(jié)果如下:
所以當(dāng)其中一個(gè)加的時(shí)候,另一個(gè)也加,效果如下:
注意:
1. 引用和實(shí)體的類(lèi)型要相同,魯迅和周樹(shù)人都是人
2. 引用在定義時(shí)必須初始化
3. 一個(gè)變量可以多個(gè)引用,也就是可以多個(gè)別名
4. 引用一個(gè)實(shí)體就不能再引用其他的實(shí)體,魯迅是周樹(shù)人的別名,就不能再用“魯迅”代指張三了
5. 引用不能作函數(shù)局部變量的返回值,因?yàn)榉祷刂档目臻g在退出函數(shù)之后就銷(xiāo)毀了,而引用與它共用一塊空間,所以此時(shí)為非法訪(fǎng)問(wèn)空間。當(dāng)然,如果是全局變量/函數(shù)外局部變量/靜態(tài)變量/堆上變量也是可以的作為返回值的。
???????
【使用方式】
1. 輸出型參數(shù)
#include <iostream>
using namespace std;
?
void Swap1(int& x, int& y)
{int temp = x;x = y;y = temp;
} //節(jié)省拷貝的空間,在傳大的對(duì)象時(shí)對(duì)比更加明顯
?
void Swap2(int* m, int* n)
{int temp = *m;*m = *n;*n = temp;
} //需要額外開(kāi)辟一塊空間存臨時(shí)變量
?
int main()
{int a = 1, b = 2;Swap1(a, b);cout << a << " " << b << endl;int c = 1, d = 2;Swap2(&c, &d);cout << c << " " << d << endl;
?return 0;
}
2. 函數(shù)返回值(注意返回局部變量時(shí)不可用)
#include <time.h>
#include <iostream>
using namespace std;struct A
{ int a[10000];
};A a; A TestFunc1()
{ return a;
}A& TestFunc2()
{ return a;
}int main()
{size_t begin1 = clock();for (size_t i = 0; i < 100000; ++i)TestFunc1();size_t end1 = clock();size_t begin2 = clock();for (size_t i = 0; i < 100000; ++i)TestFunc2();size_t end2 = clock();cout << "TestFunc1 time:" << end1 - begin1 << endl;cout << "TestFunc2 time:" << end2 - begin2 << endl;return 0;
}
這效率,贏麻了!
有小伙伴又要問(wèn)了,引用這么香,誰(shuí)還用指針呀?
那我們就得來(lái)看看指針和引用的區(qū)別了:【面試考點(diǎn)】
語(yǔ)法:
- 引用是別名,不開(kāi)空間,指針是地址,需要開(kāi)空間存地址
- 引用必須初始化,指針可以初始化也可以不初始化
- 引用不能改變指向,指針可以(不可替代的關(guān)鍵)
- 引用相對(duì)更安全,沒(méi)有空引用,但是有空指針,容易出現(xiàn)野指針,但是不容易出現(xiàn)野引用
- sizeof(引用為引用類(lèi)型的大小,指針為地址的大小)、++(引用實(shí)體+1,指針偏移一個(gè)類(lèi)型的大小)、解引用訪(fǎng)問(wèn)(引用不用解引用)等方面的區(qū)別
底層:
匯編層面上,沒(méi)有引用,都是指針,引用編譯后也轉(zhuǎn)換成指針了
總結(jié):C++的引用,對(duì)指針使用比較復(fù)雜的場(chǎng)景進(jìn)行一些替換,讓代碼更簡(jiǎn)單易懂,但是不能完全替代指針,因?yàn)橐枚x后,不能改變指向
【常引用】
如果我需要一個(gè)不可被修改的別名,就會(huì)使用到常引用
//代碼一:正常引用(權(quán)限平移)
int a = 10;
int& ra = a;
?
//代碼二:會(huì)報(bào)錯(cuò),本來(lái)我設(shè)的變量不可被改,但是你的引用可以改,相當(dāng)于給它的權(quán)限過(guò)大了
const int b = 10;
int& rb = b;
?
//代碼三:常引用,相當(dāng)于創(chuàng)建了一個(gè)不可修改的別名(權(quán)限縮小)
int c = 10;
const int& rc = c;//代碼四:d轉(zhuǎn)換成int需要生成臨時(shí)變量,再將臨時(shí)變量賦給rd引用,
//而臨時(shí)變量是常量,所以rd要用常量引用,此代碼沒(méi)有const是編譯錯(cuò)誤的
double d = 3.14;
const int& rd = d;
6. 內(nèi)聯(lián)函數(shù)
一般來(lái)說(shuō),函數(shù)調(diào)用都會(huì)建立棧幀,而如果有方式可以避免棧幀的調(diào)用,可以大大提高運(yùn)行的效率。
C++引入了一個(gè)關(guān)鍵字inline,以inline修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù),編譯時(shí)C++編譯器會(huì)在調(diào)用內(nèi)聯(lián)函數(shù)的地方展開(kāi)(函數(shù)調(diào)用替換為函數(shù)體),沒(méi)有函數(shù)調(diào)用建立棧幀的開(kāi)銷(xiāo),從而大大提升運(yùn)行效率。
【示例】
inline int Add(int x, int y)
{return x + y;
}int main()
{int ret = Add(3, 4);cout << ret << endl;return 0;
}
其實(shí)沒(méi)什么好說(shuō)的,就是在函數(shù)前加上inline。
不過(guò),編譯器會(huì)判斷此代碼是否大小合適,如果比較大的話(huà)還是會(huì)建立棧幀,避免在調(diào)用處展開(kāi)導(dǎo)致程序膨脹。
注意:
1. 不能是遞歸的函數(shù),且最好規(guī)模較小、頻繁調(diào)用的函數(shù)。
2. 不建議聲明和定義分離,分離會(huì)導(dǎo)致鏈接錯(cuò)誤。因?yàn)閕nline被展開(kāi),就沒(méi)有函數(shù)地址了,鏈接就會(huì)找不到。
【拓展】
【面試考點(diǎn)】如果在頭文件中包含了一個(gè)函數(shù)的聲明和定義,導(dǎo)致出現(xiàn)鏈接錯(cuò)誤,該如何處理?
1. 聲明和定義分離
2. 用static修飾函數(shù),鏈接屬性只在當(dāng)前文件可見(jiàn),不會(huì)進(jìn)符號(hào)表(大函數(shù))
3. inline修飾,沒(méi)有進(jìn)符號(hào)表,不會(huì)出現(xiàn)鏈接沖突
有小伙伴就要問(wèn)了,好像C語(yǔ)言里的宏也可以做到類(lèi)似的效果(不建立棧幀就能調(diào)用)呀?
但是宏也是有缺點(diǎn)的,詳細(xì)的內(nèi)容可看這篇文章-鏈接
在C++中,有很多設(shè)計(jì)都可以替代宏:const,enum,inline
7. auto關(guān)鍵字
在C++中,有的類(lèi)型的名字會(huì)很長(zhǎng),所以很容易會(huì)出錯(cuò),而這就引出了auto關(guān)鍵字
這個(gè)關(guān)鍵字的作用就是自動(dòng)識(shí)別類(lèi)型
當(dāng)然,除了用在比較長(zhǎng)的類(lèi)型名上,還可以用于for循環(huán),這個(gè)也是C++特有的
示例如下:
int main()
{int array[] = { 1,2,3,4,5 };for (auto& e : array){e *= 2;}
?for (auto e : array){cout << e << " ";}
?return 0;
}
上面這段代碼等價(jià)于:
int main()
{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 << " ";}
?return 0;
}
可見(jiàn)這里可以省去了不少的代碼,不過(guò)要注意如果不是遍歷數(shù)組就不能這么操作了
【注意點(diǎn)】
1.????????auto聲明指針類(lèi)型時(shí),用auto和auto*沒(méi)有區(qū)別,但用auto聲明引用類(lèi)型時(shí)必須加&。
2.?auto不能作為函數(shù)參數(shù)和返回值,也不能用來(lái)聲明數(shù)組
8. 空指針nullptr
NULL可作常量0,也可作無(wú)類(lèi)型指針的常量,
一般情況下,NULL會(huì)被編譯器認(rèn)為是0常量,但是我們想用它的時(shí)候往往是當(dāng)作指針來(lái)用,為了避免會(huì)出現(xiàn)麻煩的情況,所以C++又設(shè)計(jì)了一個(gè)nullptr指針,就是表示指針空值,即(void*)0
這篇內(nèi)容很多,可以收藏下來(lái)慢慢看~感謝大家的點(diǎn)贊和支持👍