日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C++命名空間?缺省參數?const總結?引用總結?內聯函數?auto關鍵字詳解_C 語言

作者:一只少年AAA ? 更新時間: 2023-02-09 編程語言

命名空間

概述

在C/C++中,變量、函數和后面要學到的類都是大量存在的,這些變量、函數和類的名稱將都存在于全局作用域中,可能會導致很多沖突。使用命名空間的目的是對標識符的名稱進行本地化,以避免命名沖突或名字污染,namespace關鍵字的出現就是針對這種問題的。

舉個例子:

#include <stdio.h>
#include <stdlib.h>

int rand = 10;

int main()
{
	printf("%d", rand);
	return 0;
}

程序編譯的結果顯示rand重定義了,為什么會這樣呢?因為在stdlib.h這個頭文件中已經定義了rand這樣一個函數,這樣就導致了編譯器不知道這是一個函數還是一個變量,C語言中無法應對這種沖突,只能通過改名字來避免。

而C++為了解決這個問題,引入了命名空間的概念。

命名空間的定義

定義命名空間,需要使用到namespace關鍵字,后面跟命名空間的名字,然后接一對{}即可,{}中即為命名空間的成員。

//命名空間
//A就是命名空間的名字
namespace A{
	int a;
	void func()
	{}
}

注意事項:

  • 命名空間只能寫在全局
  • 命名空間可以嵌套命名空間
  • 命名空間是開放的,隨時可以加入新的成員,但是新加入的成員只能在加入后使用
  • 匿名命名空間就類似于static
  • 命名空間可以取別名
  • 分文件編寫的時候,如果頭文件有兩個命名空間,但是里面的成員函數或者成員變量同名的時候,在cpp重實現函數需要加上命名空間

接下來給一個完整的代碼塊來展示命名空間的注意事項和使用:

#include<iostream> //引入頭文件
#include<string>//C++中的字符串
using namespace std; //標準命名空間
//A就是命名空間的名字
namespace A
{	
	//命名空間內既可以定義變量也可以定義函數
	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;
	}
}
//命名空間是開放的,隨時可以加入新成員,但是新成員只能在加入后使用
namespace B
{
	int c;//此時c會合并到命名空間B中,實際上就是個合并的過程
}
//匿名命名空間
namespace 
{
	int d = 5;//命名空間沒有名字,就類似于static int d = 50,是個靜態全局變量,別的文件無法使用
}
int main()
{
	//命名空間的使用
	//1.::作用域限定符
	//訪問A空間的Sub函數
	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關鍵字

引入using關鍵字之后,命名空間的使用又變得不一樣

  • 用using將命名空間的成員引入
namespace A
{
	int a = 10;
}
void test01()
{
	//using聲明的意思就是讓命名空間中某個標識符可以直接使用
	using A::a;
	cout<<a<<endl;
}

注意:

1.使用using聲明,就不會每次寫A::a了,直接用a就可以

2.using A::a聲明的意思就是把變量a又在test函數中定義了一次,此時如果在test內部再定義一個int a;就會出錯

  • 用using namespace 命名空間名稱引入
namespace A
{
	int a = 10;
}
using namespace A;
void test01()
{
	cout<<a<<endl;
}

使用using關鍵字修飾namespace整個命名空間,實際上就是脫去了這個命名空間的外衣,就等價于你定義了一個int a在全局

思考一個問題:下面代碼有錯嗎?

在test01函數體內又定義了一個int a,會報錯么?如果不報錯,那么輸出的是全局的 a = 10 還是局部的a = 20?

namespace A
{
	int a = 10;
}
using namespace A;
void test01()
{
	int a = 20;
	cout<<a<<endl;
}

答案是不會報錯,輸出的是局部的20,因為命名空間A內部的變量a在使用using關鍵字后相當于在全局定義了一個int a ;而在函數體內定義一個局部的 int a;兩個變量的作用域不同,是可以定義同名變量的,輸出的是局部變量的值,小伙伴的要注意區分~

C++輸入和輸出

  • C語言用的是printf和scanf進行輸入和輸出的。那么C++是用什么來進行輸入輸出的呢?
  • C++用到的是cout(控制臺)和cin(鍵盤)兩個函數進行操作,使用是必須包含iostream的頭文件及 std標準命名空間。
  • C++頭文件不帶.h,將std標準命名空間進行展開。
#include <iostream>
using namespace std;// 將std標準命名空間進行展開

int main()
{
	cout << "hello world" << endl;
	// std::cout << "hello world" << endl; 也可以這樣寫就不展開std標準命名空間
	return 0;
}

使用C++輸入輸出更方便,不需增加數據格式控制,比如:整形–%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;
}

運行結果如下:

缺省參數

概念:

缺省參數是聲明或定義函數時為函數的參數指定一個默認值。在調用該函數時,如果沒有指定實參則采用該默認值,否則使用指定的實參。

void PrintNum(int n = 0)
{
	cout &lt;&lt; n &lt;&lt; endl;
}

int main()
{
	PrintNum();// 無參數時,使用參數的默認值
	PrintNum(10);// 有參數時,使用指定的實參
	system("pause");
	return EXIT_SUCCESS;
}

全缺省參數

參數都要一個默認值,給定的實參依次從左向右給形參賦值

注意:我們在調用函數時,只能缺省最右邊的若干個參數,形如:Fun(4, , 6);這種調用是錯誤的調用方法。

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();
	Func(1);
	Func(1, 2);
	Func(1, 2, 3);
	system("pause");
	return EXIT_SUCCESS;
}

運行結果如下:

半缺省參數

只有部分形參給定了默認值,半缺省參數必須從右往左依次來給出,不能間隔著給。

值得注意的是,缺省參數只能為最右邊的若干個

形如:void Fun(int a=10, int b, int c = 30) { }這樣的語句是錯誤的用法。

形如:Fun(1, ,3)這種調用也是錯誤的。

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;
}

運行結果如下:

注意:

  • 半缺省參數必須從右向左依次給出,不能間隔著給
  • 缺省參數不能在聲明中和定義中同時出現(推薦寫在聲明中)
  • 缺省參數必須是全局變量和常量
  • C語言中不支持缺省參數

const限定符

const修飾符的作用

  • const類型定義: 指明變量或對象的值是不能被更新,引入目的是為了取代預編譯指令
  • 可以保護被修飾的東西,防止意外的修改,增強程序的健壯性
  • 編譯器通常不為普通const常量分配存儲空間,而是將它們保存在符號表中,這使得它成為一個編譯期間的常量,沒有了存儲與讀內存的操作,使得它的效率也很高
  • 可以節省空間,避免不必要的內存分配

規則

  • const離誰近,誰就不能被修改
  • const修飾一個變量時,一定要給這個變量初始化,若不初始化,在后面也不能初始化

分類

  常變量:  const 類型說明符 變量名

  常引用:  const 類型說明符 &引用名

  常對象:  類名 const 對象名

  常成員函數:  類名::fun(形參) const

  常數組:  類型說明符 const 數組名[大小]    

  常指針:  const 類型說明符* 指針名 ,類型說明符* const 指針名

const全局/局部變量

C

在C語言中const修改全局變量是存儲在全局區(即靜態存儲區),修飾局部變量時存儲在棧區

//const修飾的常量
const int a = 10;//全局const常量,放在常量區,受到常量區的保護
void test01()
{
	//直接修改失敗
	a = 100;
	//間接修改失敗
	int *p = &a;
	*p = 100;
}
  • 全局的const修飾的變量本質就是常量,全局const修飾的變量放在常量區中,不能通過變量名直接修改也不可以通過地址來間接修改
//局部conts修飾常量
void test02()
{
	conts int b = 10;//數據放在棧區,是個偽常量
	//直接修改失敗
	b = 100;
	//間接修改成功
	int *p = &b;
	*p = 100;
}
  • 局部const修飾的變量是個偽常量,不是真正意義上的常量,數據存放在棧區而不是常量區,可以間接修改但是不能直接修改。

總結:

  • C語言的const修飾的全局變量和局部變量都有空間
  • C語言的const修飾的全局變量具有外部鏈接屬性,可以采用extern聲明在別的文件中使用

C++

在C++中編譯器會自動優化,會將常量的數值直接替換(類似于宏定義),這導致了const局部變量與真實值產生了不一致。(常量折疊現象),而C語言會先去內存中尋找,然后替換

舉個例子:

const int aa = 10;//沒有內存
void test01()
{
	cout << aa << endl;//在編譯階段,編譯器會自動優化,將aa直接替換成常量10
	const int bb = 20;//棧區
	int *p = (int *)&bb;
	*p = 200;
	cout << bb << endl;//輸出的還是20,還是那句話,在編譯階段代碼中的bb就已經全部被替換成20,此時其實輸出的是這樣的cout << 20 << endl;但是變量bb此時的值已經被改變了,變成了200,但是由于編譯器優化,造成了常量折疊現象
}

總結:

  • C++語言的const修飾的變量有時有空間,有時沒有空間(發生常量折疊,且沒有對變量進行取地址操作)
  • C++中,const修飾的全局變量具有內部鏈接屬性,也就是說,無法使用別的文件的const修飾的變量,但是這種規則依舊可以打破
  • const修飾的全局變量永遠都沒有內存,永遠無法修改它的值,但是const修飾的局部變量可以有空間,可以修改它的值

編譯器不能優化的情況

  • 不能優化自定義數據類型
  • 如果用變量給const修飾的局部變量賦值,那么編譯器也不能優化
  • 使用extern和voaltile關鍵字來阻止優化

例子一:用變量給const修飾的局部變量賦值

void test03()
{
	int a =10;
	const int b = a;
	int *p = (int *)&b;
	*p = 100;
	cout << b << endl;//輸出100
}

例子二:利用關鍵字阻止優化

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;
}

例子三:自定義數據類型不能優化

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修飾指針

涉及到兩個很重要的概念,頂層const底層const

從 const 指針開始說起。const int* pInt;?和?int *const pInt = &someInt;,前者是?*pInt?不能改變,而后者是?pInt?不能改變。因此指針本身是不是常量和指針所指向的對象是不是常量就是兩個互相獨立的問題。用頂層表示指針本身是個常量,底層表示指針所指向的對象是個常量。更一般的,頂層 const 可以表示任意的對象是常量,這一點對任何數據類型都適用;底層 const 則與指針和引用等復合類型有關,比較特殊的是,指針類型既可以是頂層 const 也可以是底層 const 或者二者兼備。

int a = 1;
int b = 2;
const int* p1 = &a;//指針常量(頂層const)
int* const p2 = &a;//常量指針(底層const)
1.指針常量(指針不可改,指針指向的對象可改)

int a = 10;
int b = 5;
int * const p1 = &a;
p1 = &b; //指針不可改,不合法
*p1 = b; //指針指向的對象可改,合法

2.常量指針(指針可改,指針指向的對象不可改)
int a = 10;
int b = 5;
const int* p2 = &a;
p2 = &b; //指針可改, 合法
*p2 = b; //不合法

拷貝與頂層和底層 const

int i = 0;
int *const p1 = &i;     //  不能改變 p1 的值,這是一個頂層
const int ci = 42;      //  不能改變 ci 的值,這是一個頂層
const int *p2 = &ci;    //  允許改變 p2 的值,這是一個底層
const int *const p3 = p2;   //  靠右的 const 是頂層 const,靠左的是底層 const
const int &r = ci;      //  所有的引用本身都是頂層 const,因為引用一旦初始化就不能再改為其他對象的引用,這里用于聲明引用的 const 都是底層 const

const修飾引用

常引用所引用的對象不能更新,使用方法為:const 類型說明符 &引用名

非const引用只能綁定非const對象,const引用可以綁定任意對象,并且都當做常對象

常引用經常用作形參,防止函數內對象被意外修改。對于在函數中不會修改其值的參數,最好都聲明為常引用。復制構造函數的參數一般均為常引用

class Example{
public:
    Example(int x, int y):a(x),b(y){}
    Example(const Example &e):a(e.a),b(e.b){} //復制構造函數
    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修飾函數參數

const修飾參數是為了防止函數體內可能會修改參數原始對象。因此,有三種情況可討論:

  • 1、函數參數為值傳遞:值傳遞(pass-by-value)是傳遞一份參數的拷貝給函數,因此不論函數體代碼如何運行,也只會修改拷貝而無法修改原始對象,這種情況不需要將參數聲明為const。
  • 2、函數參數為指針:指針傳遞(pass-by-pointer)只會進行淺拷貝,拷貝一份指針給函數,而不會拷貝一份原始對象。因此,給指針參數加上頂層const可以防止指針指向被篡改,加上底層const可以防止指向對象被篡改。
  • 3、函數參數為引用:引用傳遞(pass-by-reference)有一個很重要的作用,由于引用就是對象的一個別名,因此不需要拷貝對象,減小了開銷。這同時也導致可以通過修改引用直接修改原始對象(畢竟引用和原始對象其實是同一個東西),因此,大多數時候,推薦函數參數設置為pass-by-reference-to-const。給引用加上底層const,既可以減小拷貝開銷,又可以防止修改底層所引用的對象。
void Fun(const A *in); //修飾指針型傳入參數
void Fun(const A &in); //修飾引用型傳入參數

void func (const int& n)
{
     n = 10;        // 編譯錯誤 
}

const修飾函數返回值

const修飾函數返回值的含義和用const修飾普通變量以及指針的含義基本相同。這樣可以防止外部對 object 的內部成員進行修改。

const int* func()   // 返回的指針所指向的內容不能修改
{
    // return p;
}

const成員函數和數據成員

類的常成員函數

由于C++會保護const對象不被更新,為了防止類的對象出現意外更新,禁止const對象調用類的非常成員函數。因此,常成員函數為常對象的唯一對外接口。

常成員函數的聲明方式:類型說明符 函數名(參數表) const

  • const對象只能訪問const成員函數,而非const對象可以訪問任意的成員函數,包括const成員函數
  • const對象的成員是不能修改的,而通過指針維護的對象卻是可以修改的
  • const成員函數不可以修改對象的數據,不管對象是否具有const性質。編譯時以是否修改成員數據為依據進行檢查
class A
{
public:
	//返回值的類型是int &類型
    int& getValue() const
    {
        // a = 10;    // 錯誤
        return a;
    }

private:
    int a;            // 非const成員變量
};

注意事項:

  • 常成員函數的定義和聲明都要含有const關鍵字
  • 一個函數是否含有const關鍵字可以作為重載函數,const對象默認調用const函數,非const對象默認調用非const函數,如果沒有非const函數,也可以調用const函數
  • const函數中不能更新目的對象的任何成員(mutable修飾的變量除外,這里不展開闡述),以此方法來保證const對象不被修改
  • 如果const成員函數想修改成員變量值,可以用mutable修飾目標成員變量

類的常數據成員

類的數據成員不能在任何函數中被賦值或修改,但必須在構造函數中使用初始化列表的方式賦初值,因為const修飾的對象必須初始化。
舉個例子,剛才的類如果a, b為常數據成員,則應該改寫為如下形式:

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;}

如果為靜態常數據成員,由于不屬于具體對象,所以不能在構造函數里賦值,仍然應該在類外賦值。特別地,如果靜態常量為整數或枚舉類型,C++允許在類內定義時指定常量值。
比如以下兩種方式均合法:

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; //靜態常量
};
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; //靜態常量
};
const int Example::c = 10;

const修飾類對象

用const修飾的類對象,該對象內的任何成員變量都不能被修改。
因此不能調用該對象的任何非const成員函數,因為對非const成員函數的調用會有修改成員變量的企圖。

class A
{
 public:
    void funcA() {}
    void funcB() const {}
};
int main
{
    const A a;
    a.funcB();    // 可以
    a.funcA();    // 錯誤

    const A* b = new A();
    b->funcB();    // 可以
    b->funcA();    // 錯誤
}

const與宏定義的區別

(1) 編譯器處理方式不同
  define宏是在預處理階段展開。
  const常量是編譯運行階段使用。

(2) 類型和安全檢查不同
  define宏沒有類型,不做任何類型檢查,僅僅是展開。
  const常量有具體的類型,在編譯階段會執行類型檢查。

(3) 存儲方式不同
  define宏僅僅是展開,有多少地方使用,就展開多少次,不會分配內存。
  const常量會在內存中分配(可以是堆中也可以是棧中)。

(4)作用范圍不同

? const有作用域,而define不重視作用域,默認定義處到文件結束,如果定義在指定作用域下有效的常量,那么define不能用。

(5)const 可以節省空間,避免不必要的內存分配。 例如:

  #define PI 3.14159 //常量宏  
    const doulbe Pi=3.14159; //此時并未將Pi放入ROM中 ......  
    double i=Pi; //此時為Pi分配內存,以后不再分配!  
    double I=PI; //編譯期間進行宏替換,分配內存  
    double j=Pi; //沒有內存分配  
    double J=PI; //再進行宏替換,又一次分配內存!  

const定義常量從匯編的角度來看,只是給出了對應的內存地址,而不是像#define一樣給出的是立即數,所以,const定義的常量在程序運行過程中只有一份拷貝,而 #define定義的常量在內存中有若干個拷貝。

const與static的區別

static

1、static局部變量 將一個變量聲明為函數的局部變量,那么這個局部變量在函數執行完成之后不會被釋放,而是繼續保留在內存中

2、static 全局變量 表示一個變量在當前文件的全局內可訪問

3、static 函數 表示一個函數只能在當前文件中被訪問

4、static 類成員變量 表示這個成員為全類所共有

5、static 類成員函數 表示這個函數為全類所共有,而且只能訪問靜態成員變量

static關鍵字的作用

(1)函數體內static變量的作用范圍為該函數體,該變量的內存只被分配一次,因此其值在下次調用時仍維持上次的值
(2)在模塊內的static全局變量和函數可以被模塊內的函數訪問,但不能被模塊外其它函數訪問
(3)在類中的static成員變量屬于整個類所擁有,對類的所有對象只有一份拷貝
(4)在類中的static成員函數屬于整個類所擁有,這個函數不接收this指針,因而只能訪問類的static成員變量

const關鍵字的作用

(1)阻止一個變量被改變
(2)聲明常量指針和指針常量
(3)const修飾形參,表明它是一個輸入參數,在函數內部不能改變其值
(4)對于類的成員函數,若指定其為const類型,則表明其是一個常函數,不能修改類的成員變量
(5)對于類的成員函數,有時候必須指定其返回值為const類型,以使得其返回值不為”左值”

引用

概念

引用不是新定義一個變量,而是給已存在變量取了一個別名,編譯器不會為引用變量開辟內存空間,它和它引用的變量共用同一塊內存空間。也就好比我們給同學取了一個外號一樣。
用法:?類型&引用變量名(對象名)= 引用實體;

int main()
{
	int a = 10;
	int& ra = a;// ra是a的引用

	cout << a << endl;
	cout << ra << endl;

	system("pause");
	return EXIT_SUCESS;
}

特性及注意事項

  • 引用在定義的時候必須初始化
  • 一個變量可有多個引用
  • 引用一個引用一個實體,無法再引用其他實體

Type& ref = val;

注意事項:

  • &在此不是取地址運算符,而是起到一個標識的作用
  • 類型標識符指的是目標變量的類型
  • 引用初始化之后不能改變
  • 不能有NULL引用,必須確保引用是和一塊合法的存儲單元關聯
int a = 10;
int b = 20;

//int& ra;//引用必須初始化

int& ra = a;
int& rra = a;

//int& ra = b;//引用一旦初始化,不能改變它的指向
//int& raaa = NULL;//NULL本身就是不合法的,不能綁定不合法的空間

數組的引用

int arr[] = {1, 2, 3, 4, 5};
//三種方式
//1.定義數組類型
typedef int(MY_ARR)[5];
MY_ARR &arref = arr;//建立引用,int &b = a

//2.直接定義引用
int(&arref2)[5] = arr;

//3.建立引用數組類型
typedef int(&MY_ARR3)[5];
MY_ARR3 arref3 = arr;

引用的使用場景

//1.作為函數的參數
void func(int &a, int &b)
{
	cout << a+b << endl;
}
//2.引用作為函數的返回值
int& func2()
{
	int b = 10;//不能返回局部變量的引用
	int &p = b;
	return p;//錯誤的
}
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;
//--------------上面的代碼都是錯誤的,這里解釋一下
//int& q = func2();實際上就是int&q = p,但是fun2函數執行完了之后,局部變量全部被銷毀了,所以int&q = 就指向了一個非法的區域,但是編譯器沒有檢測出來,具體原因是什么不清楚
	func3() = 100;
	cout << func3() << endl;
}

引用做返回值時,一般分兩種情況:返回的對象未歸還系統和返回的對象歸還系統。如果返回對象不歸還系統,我們可以引用返回,否則就需要傳值返回

想要返回局部變量:1.把局部變量寫在堆區 2.把局部變量寫在靜態區

常引用

注意:

  • 字面不能賦給引用,但是可以賦給const引用
  • const修飾的引用,不能修改
//普通引用
int a = 10;
int &ref = a;
ref = 20;
//int &ref2 = 10不能給字面量取別名,因為10這個字面量在內存中沒有空間,存儲在寄存器中

//常引用
const int &ref3 = 10;//可以給const修飾的引用賦予字面量
//編譯器會把上面的代碼變為:int tmp = 10;const int &ref3 = tmp;

內聯函數

inline修飾的函數叫做內聯函數,編譯時C++編譯器會在調用內聯函數的地方展開,沒有函數壓棧的開銷,內聯函數提升程序運行的效率。

inline int Add(int x, int y)
{
	return x + y;
}

int main()
{
	int z = Add(1, 2);
	return 0;
}

如果加了inline關鍵字,編譯器在編譯期間會用函數體替換函數的調用(類似于宏定義,在編譯階段就替換函數調用,將函數調用直接展開,減少了調用的時間,但是空間消耗巨大)。

下面是內斂函數的幾個特性:

1.inline是一種以空間換時間的做法,省去調用函數額開銷。所以代碼很長或者有循環/遞歸的函數不適宜使用作為內聯函數。
2.inline對于編譯器而言只是一個建議,編譯器會自動優化,如果定義為inline的函數體內有循環/遞歸等等,編譯器優化時會忽略掉內聯(是否稱為內聯函數由編譯器決定)。
3.inline不建議聲明和定義分離,分離會導致鏈接錯誤。因為inline被展開,就沒有函數地址了,鏈接就會找不到。

例子:一個相同的函數,一個加了inline 關鍵字,一個沒加,加上一個函數要執行10條指令,文兩個函數分別調用1000次要執行多少條指令?
普通函數:1000+10(一次調用1次指令,加起來就是1000條,每次調用都是call函數,函數不展開就是10條)
內聯函數:1000*10條指令(展開就是每次調用都是10條指令)
所以說,內聯函數展開,會讓程序變大,所以代碼很短的函數可以考慮有內聯,長函數和遞歸函數不適合用內聯。

auto關鍵字

C++11中,標準委員會賦予了auto全新的含義即:auto不再是一個存儲類型指示符,而是作為一個新的類型指示符來指示編譯器,auto聲明的變量必須由編譯器在編譯時期推導而得。

int a = 10;
auto b = a;// 自動推導b的類型為int
auto c = 'c';// 自動推導類型為char

cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
//auto d;必須初始化

有一下幾種用法:

  • auto與指針和引用結合起來使用(auto和auto*無區別)
int a = 10;
// auto和auto*無區別
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;

運行結果如下:

  • 在同一行定義多個變量(這些變量類型必須相同,編譯器只對第一個類型進行推導)
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不能推導的兩個常見

  • auto不能作為函數的參數
  • auto不能直接用來聲明數組

原文鏈接:https://www.cnblogs.com/yzsn12138/p/16890078.html

欄目分類
最近更新