C++命名空間?缺省參數(shù)?const總結(jié)?引用總結(jié)?內(nèi)聯(lián)函數(shù)?auto關(guān)鍵字詳解
命名空間
概述
在C/C++中,變量、函數(shù)和后面要學(xué)到的類都是大量存在的,這些變量、函數(shù)和類的名稱將都存在于全局作用域中,可能會(huì)導(dǎo)致很多沖突。使用命名空間的目的是對(duì)標(biāo)識(shí)符的名稱進(jìn)行本地化,以避免命名沖突或名字污染,namespace關(guān)鍵字的出現(xiàn)就是針對(duì)這種問題的。
舉個(gè)例子:
#include <stdio.h> #include <stdlib.h> int rand = 10; int main() { printf("%d", rand); return 0; }
程序編譯的結(jié)果顯示rand重定義了,為什么會(huì)這樣呢?因?yàn)樵?strong>stdlib.h這個(gè)頭文件中已經(jīng)定義了rand這樣一個(gè)函數(shù),這樣就導(dǎo)致了編譯器不知道這是一個(gè)函數(shù)還是一個(gè)變量,C語言中無法應(yīng)對(duì)這種沖突,只能通過改名字來避免。
而C++為了解決這個(gè)問題,引入了命名空間的概念。
命名空間的定義
定義命名空間,需要使用到namespace關(guān)鍵字,后面跟命名空間的名字,然后接一對(duì){}即可,{}中即為命名空間的成員。
//命名空間 //A就是命名空間的名字 namespace A{ int a; void func() {} }
注意事項(xiàng):
- 命名空間只能寫在全局
- 命名空間可以嵌套命名空間
- 命名空間是開放的,隨時(shí)可以加入新的成員,但是新加入的成員只能在加入后使用
- 匿名命名空間就類似于static
- 命名空間可以取別名
- 分文件編寫的時(shí)候,如果頭文件有兩個(gè)命名空間,但是里面的成員函數(shù)或者成員變量同名的時(shí)候,在cpp重實(shí)現(xiàn)函數(shù)需要加上命名空間
接下來給一個(gè)完整的代碼塊來展示命名空間的注意事項(xiàng)和使用:
#include<iostream> //引入頭文件 #include<string>//C++中的字符串 using namespace std; //標(biāo)準(zhǔn)命名空間 //A就是命名空間的名字 namespace A { //命名空間內(nèi)既可以定義變量也可以定義函數(shù) int rand = 10; int Sub(int x, int y) { return x + y; } struct ListNode { int data; struct ListNode* next; }; } //命名空間的嵌套定義 namespace B { int rand; namespace C { int rand; } } //命名空間是開放的,隨時(shí)可以加入新成員,但是新成員只能在加入后使用 namespace B { int c;//此時(shí)c會(huì)合并到命名空間B中,實(shí)際上就是個(gè)合并的過程 } //匿名命名空間 namespace { int d = 5;//命名空間沒有名字,就類似于static int d = 50,是個(gè)靜態(tài)全局變量,別的文件無法使用 } int main() { //命名空間的使用 //1.::作用域限定符 //訪問A空間的Sub函數(shù) cout << A::Sub(10, 20) << endl; //2.訪問嵌套空間 //訪問B空間的C空間的rand變量 B::C::rand = 5; cout << B::C::rand << endl; system("pause"); return EXIT_SUCCESS; }
using關(guān)鍵字
引入using關(guān)鍵字之后,命名空間的使用又變得不一樣
- 用using將命名空間的成員引入
namespace A { int a = 10; } void test01() { //using聲明的意思就是讓命名空間中某個(gè)標(biāo)識(shí)符可以直接使用 using A::a; cout<<a<<endl; }
注意:
1.使用using聲明,就不會(huì)每次寫A::a了,直接用a就可以
2.using A::a聲明的意思就是把變量a又在test函數(shù)中定義了一次,此時(shí)如果在test內(nèi)部再定義一個(gè)int a;就會(huì)出錯(cuò)
- 用using namespace 命名空間名稱引入
namespace A { int a = 10; } using namespace A; void test01() { cout<<a<<endl; }
使用using關(guān)鍵字修飾namespace整個(gè)命名空間,實(shí)際上就是脫去了這個(gè)命名空間的外衣,就等價(jià)于你定義了一個(gè)int a在全局
思考一個(gè)問題:下面代碼有錯(cuò)嗎?
在test01函數(shù)體內(nèi)又定義了一個(gè)int a,會(huì)報(bào)錯(cuò)么?如果不報(bào)錯(cuò),那么輸出的是全局的 a = 10 還是局部的a = 20?
namespace A { int a = 10; } using namespace A; void test01() { int a = 20; cout<<a<<endl; }
答案是不會(huì)報(bào)錯(cuò),輸出的是局部的20,因?yàn)槊臻gA內(nèi)部的變量a在使用using關(guān)鍵字后相當(dāng)于在全局定義了一個(gè)int a ;而在函數(shù)體內(nèi)定義一個(gè)局部的 int a;兩個(gè)變量的作用域不同,是可以定義同名變量的,輸出的是局部變量的值,小伙伴的要注意區(qū)分~
C++輸入和輸出
- C語言用的是printf和scanf進(jìn)行輸入和輸出的。那么C++是用什么來進(jìn)行輸入輸出的呢?
- C++用到的是cout(控制臺(tái))和cin(鍵盤)兩個(gè)函數(shù)進(jìn)行操作,使用是必須包含iostream的頭文件及 std標(biāo)準(zhǔn)命名空間。
- C++頭文件不帶.h,將std標(biāo)準(zhǔn)命名空間進(jìn)行展開。
#include <iostream> using namespace std;// 將std標(biāo)準(zhǔn)命名空間進(jìn)行展開 int main() { cout << "hello world" << endl; // std::cout << "hello world" << endl; 也可以這樣寫就不展開std標(biāo)準(zhǔn)命名空間 return 0; }
使用C++輸入輸出更方便,不需增加數(shù)據(jù)格式控制,比如:整形–%d,字符–%c
int main() { int a = 0; double b = 0.0; cin >> a; cin >> b; cout << "a = " << a << " b = " << b << endl; system("pause"); return EXIT_SUCCESS; }
運(yùn)行結(jié)果如下:
缺省參數(shù)
概念:
缺省參數(shù)是聲明或定義函數(shù)時(shí)為函數(shù)的參數(shù)指定一個(gè)默認(rèn)值。在調(diào)用該函數(shù)時(shí),如果沒有指定實(shí)參則采用該默認(rèn)值,否則使用指定的實(shí)參。
void PrintNum(int n = 0) { cout << n << endl; } int main() { PrintNum();// 無參數(shù)時(shí),使用參數(shù)的默認(rèn)值 PrintNum(10);// 有參數(shù)時(shí),使用指定的實(shí)參 system("pause"); return EXIT_SUCCESS; }
全缺省參數(shù)
參數(shù)都要一個(gè)默認(rèn)值,給定的實(shí)參依次從左向右給形參賦值
注意:我們?cè)谡{(diào)用函數(shù)時(shí),只能缺省最右邊的若干個(gè)參數(shù),形如:Fun(4, , 6);
這種調(diào)用是錯(cuò)誤的調(diào)用方法。
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() { // 實(shí)參從左向右一次給形參賦值 Func(); Func(1); Func(1, 2); Func(1, 2, 3); system("pause"); return EXIT_SUCCESS; }
運(yùn)行結(jié)果如下:
半缺省參數(shù)
只有部分形參給定了默認(rèn)值,半缺省參數(shù)必須從右往左依次來給出,不能間隔著給。
值得注意的是,缺省參數(shù)只能為最右邊的若干個(gè)。
形如:void Fun(int a=10, int b, int c = 30) { }
這樣的語句是錯(cuò)誤的用法。
形如:Fun(1, ,3)
這種調(diào)用也是錯(cuò)誤的。
void Func(int a, int b = 10, int c = 30) { cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl; } int main() { Func(1); Func(1, 2); Func(1, 2, 3); system("pause"); return EXIT_SUCCESS; }
運(yùn)行結(jié)果如下:
注意:
- 半缺省參數(shù)必須從右向左依次給出,不能間隔著給
- 缺省參數(shù)不能在聲明中和定義中同時(shí)出現(xiàn)(推薦寫在聲明中)
- 缺省參數(shù)必須是全局變量和常量
- C語言中不支持缺省參數(shù)
const限定符
const修飾符的作用
- const類型定義: 指明變量或?qū)ο蟮闹凳遣荒鼙桓?引入目的是為了取代預(yù)編譯指令
- 可以保護(hù)被修飾的東西,防止意外的修改,增強(qiáng)程序的健壯性
- 編譯器通常不為普通const常量分配存儲(chǔ)空間,而是將它們保存在符號(hào)表中,這使得它成為一個(gè)編譯期間的常量,沒有了存儲(chǔ)與讀內(nèi)存的操作,使得它的效率也很高
- 可以節(jié)省空間,避免不必要的內(nèi)存分配
規(guī)則
- const離誰近,誰就不能被修改
- const修飾一個(gè)變量時(shí),一定要給這個(gè)變量初始化,若不初始化,在后面也不能初始化
分類
常變量: const 類型說明符 變量名 常引用: const 類型說明符 &引用名 常對(duì)象: 類名 const 對(duì)象名 常成員函數(shù): 類名::fun(形參) const 常數(shù)組: 類型說明符 const 數(shù)組名[大小] 常指針: const 類型說明符* 指針名 ,類型說明符* const 指針名
const全局/局部變量
C
在C語言中const修改全局變量是存儲(chǔ)在全局區(qū)(即靜態(tài)存儲(chǔ)區(qū)),修飾局部變量時(shí)存儲(chǔ)在棧區(qū)
//const修飾的常量 const int a = 10;//全局const常量,放在常量區(qū),受到常量區(qū)的保護(hù) void test01() { //直接修改失敗 a = 100; //間接修改失敗 int *p = &a; *p = 100; }
- 全局的const修飾的變量本質(zhì)就是常量,全局const修飾的變量放在常量區(qū)中,不能通過變量名直接修改也不可以通過地址來間接修改
//局部conts修飾常量 void test02() { conts int b = 10;//數(shù)據(jù)放在棧區(qū),是個(gè)偽常量 //直接修改失敗 b = 100; //間接修改成功 int *p = &b; *p = 100; }
- 局部const修飾的變量是個(gè)偽常量,不是真正意義上的常量,數(shù)據(jù)存放在棧區(qū)而不是常量區(qū),可以間接修改但是不能直接修改。
總結(jié):
- C語言的const修飾的全局變量和局部變量都有空間
- C語言的const修飾的全局變量具有外部鏈接屬性,可以采用extern聲明在別的文件中使用
C++
在C++中編譯器會(huì)自動(dòng)優(yōu)化,會(huì)將常量的數(shù)值直接替換(類似于宏定義),這導(dǎo)致了const局部變量與真實(shí)值產(chǎn)生了不一致。(常量折疊現(xiàn)象),而C語言會(huì)先去內(nèi)存中尋找,然后替換
舉個(gè)例子:
const int aa = 10;//沒有內(nèi)存 void test01() { cout << aa << endl;//在編譯階段,編譯器會(huì)自動(dòng)優(yōu)化,將aa直接替換成常量10 const int bb = 20;//棧區(qū) int *p = (int *)&bb; *p = 200; cout << bb << endl;//輸出的還是20,還是那句話,在編譯階段代碼中的bb就已經(jīng)全部被替換成20,此時(shí)其實(shí)輸出的是這樣的cout << 20 << endl;但是變量bb此時(shí)的值已經(jīng)被改變了,變成了200,但是由于編譯器優(yōu)化,造成了常量折疊現(xiàn)象 }
總結(jié):
- C++語言的const修飾的變量有時(shí)有空間,有時(shí)沒有空間(發(fā)生常量折疊,且沒有對(duì)變量進(jìn)行取地址操作)
- C++中,const修飾的全局變量具有內(nèi)部鏈接屬性,也就是說,無法使用別的文件的const修飾的變量,但是這種規(guī)則依舊可以打破
- const修飾的全局變量永遠(yuǎn)都沒有內(nèi)存,永遠(yuǎn)無法修改它的值,但是const修飾的局部變量可以有空間,可以修改它的值
編譯器不能優(yōu)化的情況
- 不能優(yōu)化自定義數(shù)據(jù)類型
- 如果用變量給const修飾的局部變量賦值,那么編譯器也不能優(yōu)化
- 使用extern和voaltile關(guān)鍵字來阻止優(yōu)化
例子一:用變量給const修飾的局部變量賦值
void test03() { int a =10; const int b = a; int *p = (int *)&b; *p = 100; cout << b << endl;//輸出100 }
例子二:利用關(guān)鍵字阻止優(yōu)化
void test04() { const volatile int a = 7; int *p = (int *)(&a); *p = 8; cout << "a=" << a << endl;//輸出8 cout << "*p=" << *p; system("pause"); return 0; }
例子三:自定義數(shù)據(jù)類型不能優(yōu)化
struct Maker { Maker() { a = 100; } int a; }; void test05() { const Maker ma; cout << ma.a <<endl; Maker *p = (Maker*)&ma; p->a = 200;//可以修改ma中的值 cout << ma.a << endl; }
const修飾指針和引用
const修飾指針
涉及到兩個(gè)很重要的概念,頂層const和底層const
從 const 指針開始說起。const int* pInt;
和 int *const pInt = &someInt;
,前者是 *pInt
不能改變,而后者是 pInt
不能改變。因此指針本身是不是常量和指針?biāo)赶虻膶?duì)象是不是常量就是兩個(gè)互相獨(dú)立的問題。用頂層表示指針本身是個(gè)常量,底層表示指針?biāo)赶虻膶?duì)象是個(gè)常量。更一般的,頂層 const 可以表示任意的對(duì)象是常量,這一點(diǎn)對(duì)任何數(shù)據(jù)類型都適用;底層 const 則與指針和引用等復(fù)合類型有關(guān),比較特殊的是,指針類型既可以是頂層 const 也可以是底層 const 或者二者兼?zhèn)洹?/p>
int a = 1; int b = 2; const int* p1 = &a;//指針常量(頂層const) int* const p2 = &a;//常量指針(底層const) 1.指針常量(指針不可改,指針指向的對(duì)象可改) int a = 10; int b = 5; int * const p1 = &a; p1 = &b; //指針不可改,不合法 *p1 = b; //指針指向的對(duì)象可改,合法 2.常量指針(指針可改,指針指向的對(duì)象不可改) int a = 10; int b = 5; const int* p2 = &a; p2 = &b; //指針可改, 合法 *p2 = b; //不合法
拷貝與頂層和底層 const
int i = 0; int *const p1 = &i; // 不能改變 p1 的值,這是一個(gè)頂層 const int ci = 42; // 不能改變 ci 的值,這是一個(gè)頂層 const int *p2 = &ci; // 允許改變 p2 的值,這是一個(gè)底層 const int *const p3 = p2; // 靠右的 const 是頂層 const,靠左的是底層 const const int &r = ci; // 所有的引用本身都是頂層 const,因?yàn)橐靡坏┏跏蓟筒荒茉俑臑槠渌麑?duì)象的引用,這里用于聲明引用的 const 都是底層 const
const修飾引用
常引用所引用的對(duì)象不能更新,使用方法為:const 類型說明符 &引用名
非const引用只能綁定非const對(duì)象,const引用可以綁定任意對(duì)象,并且都當(dāng)做常對(duì)象
常引用經(jīng)常用作形參,防止函數(shù)內(nèi)對(duì)象被意外修改。對(duì)于在函數(shù)中不會(huì)修改其值的參數(shù),最好都聲明為常引用。復(fù)制構(gòu)造函數(shù)的參數(shù)一般均為常引用
class Example{ public: Example(int x, int y):a(x),b(y){} Example(const Example &e):a(e.a),b(e.b){} //復(fù)制構(gòu)造函數(shù) void print(); void print() const; private: const int a,b; static const int c = 10; }; void Example::print() {cout<<"print():"<<a<<ends<<b<<endl;} void Example::print() const {cout<<"print() const:"<<a<<ends<<b<<endl;}
const修飾函數(shù)參數(shù)
const修飾參數(shù)是為了防止函數(shù)體內(nèi)可能會(huì)修改參數(shù)原始對(duì)象。因此,有三種情況可討論:
- 1、函數(shù)參數(shù)為值傳遞:值傳遞(pass-by-value)是傳遞一份參數(shù)的拷貝給函數(shù),因此不論函數(shù)體代碼如何運(yùn)行,也只會(huì)修改拷貝而無法修改原始對(duì)象,這種情況不需要將參數(shù)聲明為const。
- 2、函數(shù)參數(shù)為指針:指針傳遞(pass-by-pointer)只會(huì)進(jìn)行淺拷貝,拷貝一份指針給函數(shù),而不會(huì)拷貝一份原始對(duì)象。因此,給指針參數(shù)加上頂層const可以防止指針指向被篡改,加上底層const可以防止指向?qū)ο蟊淮鄹摹?/li>
- 3、函數(shù)參數(shù)為引用:引用傳遞(pass-by-reference)有一個(gè)很重要的作用,由于引用就是對(duì)象的一個(gè)別名,因此不需要拷貝對(duì)象,減小了開銷。這同時(shí)也導(dǎo)致可以通過修改引用直接修改原始對(duì)象(畢竟引用和原始對(duì)象其實(shí)是同一個(gè)東西),因此,大多數(shù)時(shí)候,推薦函數(shù)參數(shù)設(shè)置為pass-by-reference-to-const。給引用加上底層const,既可以減小拷貝開銷,又可以防止修改底層所引用的對(duì)象。
void Fun(const A *in); //修飾指針型傳入?yún)?shù) void Fun(const A &in); //修飾引用型傳入?yún)?shù) void func (const int& n) { n = 10; // 編譯錯(cuò)誤 }
const修飾函數(shù)返回值
const修飾函數(shù)返回值的含義和用const修飾普通變量以及指針的含義基本相同。這樣可以防止外部對(duì) object 的內(nèi)部成員進(jìn)行修改。
const int* func() // 返回的指針?biāo)赶虻膬?nèi)容不能修改 { // return p; }
const成員函數(shù)和數(shù)據(jù)成員
類的常成員函數(shù)
由于C++會(huì)保護(hù)const對(duì)象不被更新,為了防止類的對(duì)象出現(xiàn)意外更新,禁止const對(duì)象調(diào)用類的非常成員函數(shù)。因此,常成員函數(shù)為常對(duì)象的唯一對(duì)外接口。
常成員函數(shù)的聲明方式:類型說明符 函數(shù)名(參數(shù)表) const
- const對(duì)象只能訪問const成員函數(shù),而非const對(duì)象可以訪問任意的成員函數(shù),包括const成員函數(shù)
- const對(duì)象的成員是不能修改的,而通過指針維護(hù)的對(duì)象卻是可以修改的
- const成員函數(shù)不可以修改對(duì)象的數(shù)據(jù),不管對(duì)象是否具有const性質(zhì)。編譯時(shí)以是否修改成員數(shù)據(jù)為依據(jù)進(jìn)行檢查
class A { public: //返回值的類型是int &類型 int& getValue() const { // a = 10; // 錯(cuò)誤 return a; } private: int a; // 非const成員變量 };
注意事項(xiàng):
- 常成員函數(shù)的定義和聲明都要含有const關(guān)鍵字
- 一個(gè)函數(shù)是否含有const關(guān)鍵字可以作為重載函數(shù),const對(duì)象默認(rèn)調(diào)用const函數(shù),非const對(duì)象默認(rèn)調(diào)用非const函數(shù),如果沒有非const函數(shù),也可以調(diào)用const函數(shù)
- const函數(shù)中不能更新目的對(duì)象的任何成員(mutable修飾的變量除外,這里不展開闡述),以此方法來保證const對(duì)象不被修改
- 如果const成員函數(shù)想修改成員變量值,可以用mutable修飾目標(biāo)成員變量
類的常數(shù)據(jù)成員
類的數(shù)據(jù)成員不能在任何函數(shù)中被賦值或修改,但必須在構(gòu)造函數(shù)中使用初始化列表的方式賦初值
,因?yàn)閏onst修飾的對(duì)象必須初始化。
舉個(gè)例子,剛才的類如果a, b為常數(shù)據(jù)成員,則應(yīng)該改寫為如下形式:
class Example{ public: Example(int x, int y):a(x),b(y){} //初始化列表方式賦初值 void print(); void print() const; private: const int a,b; }; void Example::print() {cout<<"print():"<<a<<ends<<b<<endl;} void Example::print() const {cout<<"print() const:"<<a<<ends<<b<<endl;}
如果為靜態(tài)常數(shù)據(jù)成員,由于不屬于具體對(duì)象,所以不能在構(gòu)造函數(shù)里賦值,仍然應(yīng)該在類外賦值。特別地,如果靜態(tài)常量為整數(shù)或枚舉類型,C++允許在類內(nèi)定義時(shí)指定常量值。
比如以下兩種方式均合法:
class Example{ public: Example(int x, int y):a(x),b(y){} void print(); void print() const; private: const int a,b; static const int c = 10; //靜態(tài)常量 };
class Example{ public: Example(int x, int y):a(x),b(y){} void print(); void print() const; private: const int a,b; static const int c; //靜態(tài)常量 }; const int Example::c = 10;
const修飾類對(duì)象
用const修飾的類對(duì)象,該對(duì)象內(nèi)的任何成員變量都不能被修改。
因此不能調(diào)用該對(duì)象的任何非const成員函數(shù),因?yàn)閷?duì)非const成員函數(shù)的調(diào)用會(huì)有修改成員變量的企圖。
class A { public: void funcA() {} void funcB() const {} }; int main { const A a; a.funcB(); // 可以 a.funcA(); // 錯(cuò)誤 const A* b = new A(); b->funcB(); // 可以 b->funcA(); // 錯(cuò)誤 }
const與宏定義的區(qū)別
(1) 編譯器處理方式不同
define宏是在預(yù)處理階段展開。
const常量是編譯運(yùn)行階段使用。
(2) 類型和安全檢查不同
define宏沒有類型,不做任何類型檢查,僅僅是展開。
const常量有具體的類型,在編譯階段會(huì)執(zhí)行類型檢查。
(3) 存儲(chǔ)方式不同
define宏僅僅是展開,有多少地方使用,就展開多少次,不會(huì)分配內(nèi)存。
const常量會(huì)在內(nèi)存中分配(可以是堆中也可以是棧中)。
(4)作用范圍不同
? const有作用域,而define不重視作用域,默認(rèn)定義處到文件結(jié)束,如果定義在指定作用域下有效的常量,那么define不能用。
(5)const 可以節(jié)省空間,避免不必要的內(nèi)存分配。 例如:
#define PI 3.14159 //常量宏 const doulbe Pi=3.14159; //此時(shí)并未將Pi放入ROM中 ...... double i=Pi; //此時(shí)為Pi分配內(nèi)存,以后不再分配! double I=PI; //編譯期間進(jìn)行宏替換,分配內(nèi)存 double j=Pi; //沒有內(nèi)存分配 double J=PI; //再進(jìn)行宏替換,又一次分配內(nèi)存!
const定義常量從匯編的角度來看,只是給出了對(duì)應(yīng)的內(nèi)存地址,而不是像#define一樣給出的是立即數(shù),所以,const定義的常量在程序運(yùn)行過程中只有一份拷貝,而 #define定義的常量在內(nèi)存中有若干個(gè)拷貝。
const與static的區(qū)別
static
1、static局部變量 將一個(gè)變量聲明為函數(shù)的局部變量,那么這個(gè)局部變量在函數(shù)執(zhí)行完成之后不會(huì)被釋放,而是繼續(xù)保留在內(nèi)存中
2、static 全局變量 表示一個(gè)變量在當(dāng)前文件的全局內(nèi)可訪問
3、static 函數(shù) 表示一個(gè)函數(shù)只能在當(dāng)前文件中被訪問
4、static 類成員變量 表示這個(gè)成員為全類所共有
5、static 類成員函數(shù) 表示這個(gè)函數(shù)為全類所共有,而且只能訪問靜態(tài)成員變量
static關(guān)鍵字的作用
(1)函數(shù)體內(nèi)static變量的作用范圍為該函數(shù)體,該變量的內(nèi)存只被分配一次,因此其值在下次調(diào)用時(shí)仍維持上次的值
(2)在模塊內(nèi)的static全局變量和函數(shù)可以被模塊內(nèi)的函數(shù)訪問,但不能被模塊外其它函數(shù)訪問
(3)在類中的static成員變量屬于整個(gè)類所擁有,對(duì)類的所有對(duì)象只有一份拷貝
(4)在類中的static成員函數(shù)屬于整個(gè)類所擁有,這個(gè)函數(shù)不接收this指針,因而只能訪問類的static成員變量
const關(guān)鍵字的作用
(1)阻止一個(gè)變量被改變
(2)聲明常量指針和指針常量
(3)const修飾形參,表明它是一個(gè)輸入?yún)?shù),在函數(shù)內(nèi)部不能改變其值
(4)對(duì)于類的成員函數(shù),若指定其為const類型,則表明其是一個(gè)常函數(shù),不能修改類的成員變量
(5)對(duì)于類的成員函數(shù),有時(shí)候必須指定其返回值為const類型,以使得其返回值不為”左值”
引用
概念
引用不是新定義一個(gè)變量,而是給已存在變量取了一個(gè)別名,編譯器不會(huì)為引用變量開辟內(nèi)存空間,它和它引用的變量共用同一塊內(nèi)存空間。也就好比我們給同學(xué)取了一個(gè)外號(hào)一樣。
用法: 類型&引用變量名(對(duì)象名)= 引用實(shí)體;
int main() { int a = 10; int& ra = a;// ra是a的引用 cout << a << endl; cout << ra << endl; system("pause"); return EXIT_SUCESS; }
特性及注意事項(xiàng)
- 引用在定義的時(shí)候必須初始化
- 一個(gè)變量可有多個(gè)引用
- 引用一個(gè)引用一個(gè)實(shí)體,無法再引用其他實(shí)體
Type& ref = val;
注意事項(xiàng):
- &在此不是取地址運(yùn)算符,而是起到一個(gè)標(biāo)識(shí)的作用
- 類型標(biāo)識(shí)符指的是目標(biāo)變量的類型
- 引用初始化之后不能改變
- 不能有NULL引用,必須確保引用是和一塊合法的存儲(chǔ)單元關(guān)聯(lián)
int a = 10; int b = 20; //int& ra;//引用必須初始化 int& ra = a; int& rra = a; //int& ra = b;//引用一旦初始化,不能改變它的指向 //int& raaa = NULL;//NULL本身就是不合法的,不能綁定不合法的空間
數(shù)組的引用
int arr[] = {1, 2, 3, 4, 5}; //三種方式 //1.定義數(shù)組類型 typedef int(MY_ARR)[5]; MY_ARR &arref = arr;//建立引用,int &b = a //2.直接定義引用 int(&arref2)[5] = arr; //3.建立引用數(shù)組類型 typedef int(&MY_ARR3)[5]; MY_ARR3 arref3 = arr;
引用的使用場(chǎng)景
//1.作為函數(shù)的參數(shù) void func(int &a, int &b) { cout << a+b << endl; } //2.引用作為函數(shù)的返回值 int& func2() { int b = 10;//不能返回局部變量的引用 int &p = b; return p;//錯(cuò)誤的 } int& func3() { static int b = 10; return b; } void test01() { int& q = func2(); cout << q << endl; q = 100; cout << q << endl; func2() = 200; cout << q << endl; cout << func2() << endl; //--------------上面的代碼都是錯(cuò)誤的,這里解釋一下 //int& q = func2();實(shí)際上就是int&q = p,但是fun2函數(shù)執(zhí)行完了之后,局部變量全部被銷毀了,所以int&q = 就指向了一個(gè)非法的區(qū)域,但是編譯器沒有檢測(cè)出來,具體原因是什么不清楚 func3() = 100; cout << func3() << endl; }
引用做返回值時(shí),一般分兩種情況:返回的對(duì)象未歸還系統(tǒng)和返回的對(duì)象歸還系統(tǒng)。如果返回對(duì)象不歸還系統(tǒng),我們可以引用返回,否則就需要傳值返回
想要返回局部變量:1.把局部變量寫在堆區(qū) 2.把局部變量寫在靜態(tài)區(qū)
常引用
注意:
- 字面不能賦給引用,但是可以賦給const引用
- const修飾的引用,不能修改
//普通引用 int a = 10; int &ref = a; ref = 20; //int &ref2 = 10不能給字面量取別名,因?yàn)?0這個(gè)字面量在內(nèi)存中沒有空間,存儲(chǔ)在寄存器中 //常引用 const int &ref3 = 10;//可以給const修飾的引用賦予字面量 //編譯器會(huì)把上面的代碼變?yōu)椋篿nt tmp = 10;const int &ref3 = tmp;
內(nèi)聯(lián)函數(shù)
以inline修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù),編譯時(shí)C++編譯器會(huì)在調(diào)用內(nèi)聯(lián)函數(shù)的地方展開,沒有函數(shù)壓棧的開銷,內(nèi)聯(lián)函數(shù)提升程序運(yùn)行的效率。
inline int Add(int x, int y) { return x + y; } int main() { int z = Add(1, 2); return 0; }
如果加了inline關(guān)鍵字,編譯器在編譯期間會(huì)用函數(shù)體替換函數(shù)的調(diào)用(類似于宏定義,在編譯階段就替換函數(shù)調(diào)用,將函數(shù)調(diào)用直接展開,減少了調(diào)用的時(shí)間,但是空間消耗巨大)。
下面是內(nèi)斂函數(shù)的幾個(gè)特性:
1.inline是一種以空間換時(shí)間的做法,省去調(diào)用函數(shù)額開銷。所以代碼很長或者有循環(huán)/遞歸的函數(shù)不適宜使用作為內(nèi)聯(lián)函數(shù)。
2.inline對(duì)于編譯器而言只是一個(gè)建議,編譯器會(huì)自動(dòng)優(yōu)化,如果定義為inline的函數(shù)體內(nèi)有循環(huán)/遞歸等等,編譯器優(yōu)化時(shí)會(huì)忽略掉內(nèi)聯(lián)(是否稱為內(nèi)聯(lián)函數(shù)由編譯器決定)。
3.inline不建議聲明和定義分離,分離會(huì)導(dǎo)致鏈接錯(cuò)誤。因?yàn)閕nline被展開,就沒有函數(shù)地址了,鏈接就會(huì)找不到。
例子:一個(gè)相同的函數(shù),一個(gè)加了inline 關(guān)鍵字,一個(gè)沒加,加上一個(gè)函數(shù)要執(zhí)行10條指令,文兩個(gè)函數(shù)分別調(diào)用1000次要執(zhí)行多少條指令?
普通函數(shù):1000+10(一次調(diào)用1次指令,加起來就是1000條,每次調(diào)用都是call函數(shù),函數(shù)不展開就是10條)
內(nèi)聯(lián)函數(shù):1000*10條指令(展開就是每次調(diào)用都是10條指令)
所以說,內(nèi)聯(lián)函數(shù)展開,會(huì)讓程序變大,所以代碼很短的函數(shù)可以考慮有內(nèi)聯(lián),長函數(shù)和遞歸函數(shù)不適合用內(nèi)聯(lián)。
auto關(guān)鍵字
C++11中,標(biāo)準(zhǔn)委員會(huì)賦予了auto全新的含義即:auto不再是一個(gè)存儲(chǔ)類型指示符,而是作為一個(gè)新的類型指示符來指示編譯器,auto聲明的變量必須由編譯器在編譯時(shí)期推導(dǎo)而得。
int a = 10; auto b = a;// 自動(dòng)推導(dǎo)b的類型為int auto c = 'c';// 自動(dòng)推導(dǎo)類型為char cout << typeid(b).name() << endl; cout << typeid(c).name() << endl; //auto d;必須初始化
有一下幾種用法:
- auto與指針和引用結(jié)合起來使用(auto和auto*無區(qū)別)
int a = 10; // auto和auto*無區(qū)別 auto pa1 = &a; auto* pa2 = &a; auto& ra = a;// ==> int& ra = a; cout << typeid(a).name() << endl; cout << typeid(pa1).name() << endl; cout << typeid(pa2).name() << endl; cout << typeid(ra).name() << endl;
運(yùn)行結(jié)果如下:
- 在同一行定義多個(gè)變量(這些變量類型必須相同,編譯器只對(duì)第一個(gè)類型進(jìn)行推導(dǎo))
auto a = 3, b = 4; auto c = 3.4, d = 5.5; auto i =0, *p = &i;//正確,i是整型,p是整型指針 cout << typeid(a).name() << endl; cout << typeid(b).name() << endl; cout << typeid(c).name() << endl; cout << typeid(d).name() << endl; cout << typeid(i).name() << endl; cout << typeid(p).name() << endl;
auto不能推導(dǎo)的兩個(gè)常見
- auto不能作為函數(shù)的參數(shù)
- auto不能直接用來聲明數(shù)組
到此這篇關(guān)于C++命名空間 缺省參數(shù) const總結(jié) 引用總結(jié) 內(nèi)聯(lián)函數(shù) auto關(guān)鍵字詳解的文章就介紹到這了,更多相關(guān)C++入門內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++使用TinyXml實(shí)現(xiàn)讀取XMl文件
常見C/C++?XML解析器有Tinyxml、XERCES、squashxml、xmlite、pugxml、libxml等等,本文為大家介紹的是使用TinyXml實(shí)現(xiàn)讀取XMl文件,需要的可以參考一下2023-06-06C/C++實(shí)現(xiàn)HTTP協(xié)議解析的示例代碼
基本上,HTTP?是一種基于?TCP/IP?的通信協(xié)議,用于通過?Web?傳遞?HTML?文件、圖像文件、查詢結(jié)果等數(shù)據(jù)。本文將用C/C++實(shí)現(xiàn)HTTP協(xié)議解析,感興趣的可以了解一下2022-07-07