国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

C++11 新特性詳解 1一覽表

NSFish / 1031人閱讀

摘要:不能進行隱式轉換跟它相對應的另一個關鍵字是,意思是隱藏的,類構造函數默認情況下即聲明為隱式。通過排他性來定義,每個表達式不是就是。返回容器中倒數第一個元素的常量迭代器。這種轉換的安全性也要開發人員來保證。

目錄

1.explicit關鍵字

2.左值和右值概念

3.函數返回當引用

4.C++11 _array容器用法

5.C++類型轉換簡介

5.1.static_cas轉換

5.2.reinterpreter_cast 轉換

5.3.dynamic_cast轉換

5.4.const_cast 轉換


1.explicit關鍵字

?explicit???/?k?spl?s?t/???明確的;清楚的;直率的;詳述的

作用是表明該構造函數是顯示的, 而非隱式的。不能進行隱式轉換!跟它相對應的另一個關鍵字是implicit,意思是隱藏的,類構造函數默認情況下即聲明為implicit(隱式)。

例如我們定義一個類

class student {public:	student(int age) {		this->age = age;		cout << "age=" << age << endl;	}	student(int age, string name) {		this->age = age;		this->name = name;		cout << "age=" << age << "  name=" << name << endl;	}	~student() {	}	int getAge() {		return this->age;	}	string getName() {		return this->name;	}private:	string name;	int age;};

在主函數中分別使用顯示構造和隱式構造

int main() {    //顯示構造,直接在括號里面寫	student xiaoM(18);	    //顯示構造	student xiaoH(19, "小花");		    //隱式構造	student xiaoW = 18;		        //隱式構造(C++11前編譯器無法通過)	student xiaoZ = { 19,"小張" };		system("pause");	return 0;}

執行結果

當給其中一個構造函數加上explicit關鍵字后

class student {public:	explicit student(int age) {		this->age = age;		cout << "age=" << age << endl;	}private:	string name;	int age;};

這種聲明就表示:這個構造函數只能顯示構造,無法進行隱式轉換

explicit關鍵字的作用在于:在實際開發中 等號會產生一些歧義,等號本身又有賦值的作用,無法在一瞬間辨別等號是用于賦值還是調用隱式構造,不便于閱讀。


2.左值和右值概念

我們在日常編譯程序時,有時可能會遇到如下報錯提示:

源代碼

#includeusing namespace std;int demo() {	int i = 0;	return i;}int main() {    //將函數返回作為左值	demo() = 888;    	return 0;}

這里將函數返回賦予888,編譯器給出“表達式必須是可修改的左值”的報錯提示 ,如果我們將函數返回作為右值,則不會有此報錯~


關于左值和右值的問題,這里就涉及到計算機的存儲層次結構

?存儲層次結構

例如我們計算 c = a + b ;

a 和 b 的值會保存在內存中,當程序遇到c = a + b,會將a和b的值拿到cpu的寄存器中,再將計算結果返回給內存中的c,當我們Ctrl + S后,內存中的數據就可以永久保存到磁盤中。


?左值和右值的概念

?按字面意思,通俗地說。以賦值符號 = 為界,等號(=)左邊的就是左值(lvalue),等號(=) 右邊就是右值(rvalue)。??

lvalue —— 代表一個在內存中占有確定位置的對象(換句話說就是有一個地址)。?
rvalue —— 通過排他性來定義,每個表達式不是lvalue就是rvalue。因此從上面的 ? lvalue的定義,rvalue是在不在內存中占有確定位置的表達式,而是存在在寄存器中。

所有的左值(無論是數組,函數或不完全類型)都可以轉換成右值


?我們將下面程序轉為匯編碼觀察

#includeusing namespace std;int main() {	int a = 1;	int b = 2;	int c = 3;	c = a + b;	printf("%d", c);	return 0;}

匯編代碼

程序將a、b、c的值都存儲在棧上,當執行 c= a + b 時,程序會將 a 和 b 的值拿到寄存器中計算,再將計算結果返回給內存中 c 的位置上去。


也就是說,程序執行的方式,是從內存中取值放到寄存器中,再將計算結果返回給內存中的某個位置!


a + b的結果保存在寄存器中,再將寄存器的值返回給內存

因此,對于? c = a + b;是合法的

而 a + b = c;也就是eax = c就是非法,左值需要在內存中有位置,而a + b是在寄存器?? 中


3.函數返回當引用

?上面我們講了左值與右值,當我們把函數返回值作為左值時,編譯器給出報錯提示,而C++11的新增特性“函數返回引用”又可以實現函數返回值作為左值的操作

C++引用使用時的難點:

1.當函數返回參數是引用時

????????? 若返回棧變量(自動變量/臨時變量),不能成為其它引用的初始值,不能作為左值使用。


2. 若返回靜態變量或全局變量

??????? ·可以成為其他引用的初始值

??????? ·即可作為右值使用,也可作為左值使用


? 3. ??返回形參當引用

??????? (注:C++鏈式編程中,經常用到引用,運算符重載專題) 例如在重載“<<"左移運算符后,我們想要鏈式輸出,就是返回的cout引用


下面,對第一種種情況分別通過代碼舉例 ?

1. 函數返回值為引用,返回臨時變量作為其他引用的初始值

#includeusing namespace std;int& demo() {	int i = 600;	return i;	//返回局部變量		}int main() {	int &a =demo();	//函數引用成為其他引用的初始值	cout << a << endl;	system("pause");	return 0;}

編譯結果

編譯器并未報錯,也只是給出警告 “ 返回局部變量 ” 。好像目測也沒啥問題 ,下面通過一段代碼示例,來解釋這種操作的不合理性。?看操作。


我們知道,通過引用可以將兩個變量都有同一塊地址

?


因此,對于上面的代碼,a 的地址和局部變量 i 有相同的地址

?

?我們現在更改a的值,然后再調用demo函數

int main() {	int &a = demo();	cout << "a的地址為:" <<&a<

運行結果:

第一次demo函數執行,i 的地址為00D3F854,a的地址也為00D3F854。

然后demo函數執行完畢后,在棧內的空間釋放。

第二次demo函數也是在棧的相同位置存儲,所以 i 的位置沒有改變,因此 i =600后也影響了a的值。

?

如果我們在棧中使用兩個函數,會是什么結果呢?

#include#includeusing namespace std;int demo1() {	int i = 100;	cout << "demo1()函數中,i的地址為:" << &i << endl;	return 0;}int& demo() {	int i = 600;	cout << "i的地址為:" << &i << endl;	return i;				//返回局部變量}int main() {	int &a = demo();	cout << "a的地址為:" <<&a<

執行結果

也就是說,如果用函數返回引用,返回局部變量和引用初始化,程序會繼續認為這個地址還是屬于計算機的,并非是程序員自己申請的。


2.返回局部變量作為左值

?情況與上面類似

#include#includeusing namespace std;int demo1() {	int i = 0;	cout << "demo1()函數中,i的地址為:" << &i << endl;	return 0;}int& demo(int **p) {	int i = 600;	*p = &i;	cout << "i的地址為:" << &i << " i的值為:" << i << endl;	return i;				//返回局部變量}int main() {	int* p = NULL;	demo(&p) = 888;	cout << "p的地址為:" << p << " p的值為:" << *p << endl;	demo1();	cout << "p的地址為:" << p << " p的值為:" << *p << endl;	system("pause");	return 0;}

執行結果

?總結:若返回棧變量(自動變量/臨時變量),不能成為其它引用的初始值,不能作為左值使用,雖然編譯器只會警告,但在實際開發中是非常危險的操作!


3.例如返回static或者全局變量就不出出現這種情況

#include#includeusing namespace std;int& demo() {	static int i = 600;	cout << "i的地址為:" << &i << endl;	return i;				//返回靜態變量}int main() {	int a = demo();	a = 888;	cout << "調用了demo(),a的值為:" << a << endl;	demo();	cout << "再次調用了demo(),a的值為:" << a << endl;	system("pause");	return 0;}

執行結果

其實,主要還是看返回值的生命周期,如果是立刻銷毀的,則應注意使用~


4.C++11 _array容器用法

?array容器概念?

  1. array 容器是?C++?11 標準中新增的序列容器,簡單地理解,它就是在 C++ 普通數組的基礎上,添加了一些成員函數和全局函數。
  1. array是將元素置于一個固定數組中加以管理的容器。
  2. array可以隨機存取元素,支持索引值直接存取, 用[]操作符或at()方法對元素進行操作,也可以使用迭代器訪問
  3. 不支持動態的新增刪除操作
  4. array可以完全替代C語言中的數組,使操作數組元素更加安全!
  5. #include

?array特點

  1. array 容器的大小是固定的,無法動態的擴展或收縮,這也就意味著,在使用該容器的過程無法增加或移除元素而改變其大小,它只允許訪問或者替換存儲的元素。
  2. STL?還提供有可動態擴展或收縮存儲空間的 vector 容器

?array對象的構造

?array采用模板類實現,array對象的默認構造形式

array arrayT; ???//T為存儲的類型, 為數值型模板參數

//構造函數

#includearray a1;     //一個存放5個int的array容器array a2;   //一個存放6個float的array容器array a3; //一個存放7個student的array容器

?array的賦值

array?的賦值

a1.assign(0); //玩法一?改變array中所有元素(注:將被廢棄,不推薦使用)

在目前版本,編譯器會報錯

如果非要使用assign的話可以根據報錯提示加一個宏

#define _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING 1

a1.fill(666); //玩法二 用特定值填充array中所有元素


array test={1, 2, 3, 4};// 玩法三 定義時使用初始化列表,列表內的數量不能超過定義的大小


array test;

test={1,2,3,4}; ??//玩法四 定義后使用列表重新賦值


array a1,a2;

a1={1,2,3,4};

a2 = a1;//玩法五,賦值運算


a1.swap(a2); ?//玩法六 ?和其它array進行交換

?array的大小

array.size();    返回容器中元素的個數array.empty();    判斷容器是否為空,逗你玩的,因為容器是固定大小,永遠為 falsearray.max_size();   返回容器中最大元素的個數,數組是固定大小,這也是逗你玩的同size()。

array的數據存取 ?

第一 ?使用下標操作 a1[0] = 100;

第二 ?使用at 方法 如: a1.at(2) = 100;

第三 ?接口返回的引用 a1.front() 和 a1.back() ?

注意: ??第一和第二種方式必須注意越界

array 迭代器訪問?

#includeusing namespace std;array.begin();         返回容器中第一個數據的迭代器。array.end();          返回容器中最后一個數據之后的迭代器。array.rbegin();        返回容器中倒數第一個元素的迭代器。array.rend();         返回容器中倒數最后一個元素的后面的迭代器。array.cbegin();        返回容器中第一個數據的常量迭代器。array.cend();          返回容器中最后一個數據之后的常量迭代器。array.crbegin();        返回容器中倒數第一個元素的常量迭代器。array.crend();         返回容器中倒數最后一個元素的后面的常量迭代器。
#include#includeusing namespace std;int main() {	array arrayInt = { 1,2,3,4,5 };	普通迭代器	for (array::iterator ite = arrayInt.begin(); ite != arrayInt.end(); ite++)		cout << *ite << "  ";	常量迭代器,常量迭代器無法修改	array::const_iterator ite = arrayInt.cbegin();	逆向迭代器,逆向迭代器也是++	for (array::reverse_iterator ite = arrayInt.rbegin(); ite != arrayInt.rend(); ite++)		cout << *ite << "  ";}

set.rbegin()與set.rend()。略。

5.C++類型轉換簡介

舊式轉型? C風格的強制類型

??????????????? type? b? =? (? type? )? a

??????????????? 例如:

??????????????? int i = 48;

??????????????? char? c = (char ) i;

double  PI = 3.1415926;int i = PI;   隱式轉換int i1 = (int) PI ; 強制類型轉換強制類型轉換,整數直接變指針int * addr = (int*) 0x888888;  void *p;int * int_arg = (int*) p;  強制轉換

?


?

式轉型C++風格的類型轉換提供了4種類型轉換操作符來應對不同場合的應用。

格式:

??? type b?= 類型操作符<type> (?a?)???

???????類型操作符= static_cast | reinterpreter_cast | dynamic_cast | const_cast

?


5.1.static_cas轉換

靜態類型轉換斯文的勸導,溫柔的轉換)(編譯器會檢查轉換是否合理)。如int轉換成char

char a = "A";int b = static_cast (a);

主要用法:

  • 用于類層次結構中基類(父類)和派生類(子類)之間指針或引用的轉換。上行指針或引用(派生類到基類)轉換安全,下行不安全(上行可以,下行不安全)
  • 用于基本數據類型之間的轉換,如把int轉換成char,把int轉換成enum。這種轉換的安全性也要開發人員來保證。
  • 把空指針轉換成目標類型的空指針。
  • 把任何類型的表達式轉換成void類型

?

1.用于類層次結構中基類(父類)和派生類(子類)之間指針或引用的轉換?

class Animal {public:	virtual void cry() = 0;};class dog :public Animal {public:	void cry() {		cout << "小狗汪汪汪" << endl;	}};int main() {	dog* d = new dog();	Animal* animal = d;//子類對象賦給基類	使用static_cast指針轉換	Animal* al = static_cast(d);    引用轉換	dog d2;	Animal& a2 = static_cast(d2);	system("pause");	return 0;} 

那為什么說上行轉換可以,下行轉換不安全呢?

我們再增加一個Animal的派生類

class cat :public Animal {public:	void cry() {		cout << "小貓喵喵喵" << endl;	}};
int main() {	dog* d = new dog();	//上行轉換安全	Animal* animal = static_cast(d);	//下行轉換,這種也是安全的	d = static_cast(animal);	//animal已經是dog類轉過來的,再轉成cat的就不安全的	cat* c;	c = static_cast(animal);		system("pause");	return 0;} 

因此,并不是說下行轉換不可用,例如上面的將從dog類轉過來的animal再轉到cat就是不安全的,還是取決于程序員的使用 。


2.基本數據類型之間的轉換?

int a = 10;char b = static_cast(a);

?3.把空指針轉換成目標類型的空指針。

int* p = static_cast(NULL);

NULL在C++里定義的是void*0


?4.把任何類型的表達式轉換成void類型

int* p = new int[10];void* vp = static_cast(p);

總結:使用static_cast可以使編譯器做一些合法性檢查,不寫也沒關系。

?


5.2.reinterpreter_cast 轉換

重新解釋類型(掛羊頭,賣狗肉)?不同類型間的互轉,數值與指針間的互轉

用法: ?

??????? type b?= reinterpret_cast (?a?)

????????type 必須是一個指針、引用、算術類型、函數指針。

例如強制將整數轉為指針int* addr = reinterpret_cast(0x88888);如果使用static_cast則會報錯int* addr1 = static_cast(0x88888);

?

?

忠告:濫用 reinterpret_cast 運算符可能很容易帶來風險。 除非所需轉換本身是低級別的,否則應使用其他強制轉換運算符之一。


用法1,數值與指針之間轉換?

int* p = reinterpret_cast(0x88888);int val = reinterpret_cast(p);

用法2, 不同類型指針和引用之間的轉換

?定義一個父類和兩個派生類

class Animal {public:	void cry() {		cout << "動物叫" << endl;	}};class cat :public Animal {public:	void cry() {		cout << "小貓喵喵喵" << endl;	}};class dog :public Animal {public:	void cry() {		cout << "小狗汪汪汪" << endl;	}};

1.隱式上行? 轉換? 與強制上行? 轉換

dog d1;Animal* animal = &d1;animal->cry();//如果能用static_cast強轉,static_cast優先dog* d2 = reinterpret_cast(animal);dog* d3 = static_cast(animal);

?2.不同類型指針轉換不能用static_cast

?

?


3.但是可以使用reinterpre_cast轉換

int main() {	dog d1;	cat* c1 = reinterpret_cast(&d1);	c1->cry();	system("pause");	return 0;}

編譯器不管程序是將什么類型轉的,只曉得最后要獲得一個cat類型,然后按cat的存儲類型,訪問里面的方法。如果濫用reinterpreter_cast,類型之間轉來轉去,可能會導致程序快速崩潰。


4.引用的強制類型轉換

dog d1;Animal& animal = d1;dog& d2 = reinterpret_cast(animal);

?

?reinterpreter_cast? 再加一個 static_cast 就已經可以替換C語言的轉換

?


5.3.dynamic_cast轉換

?動態類型轉換

  • 將一個基類對象指針cast到繼承類指針,dynamic_cast 會根據基類指針是否真正指向繼承類指針來做相應處理。失敗返回null,成功返回正常cast后的對象指針;
  • 將一個基類對象引用cast 繼承類對象,dynamic_cast 會根據基類對象是否真正屬于繼承類來做相應處理。失敗拋出異常bad_cast

注意dynamic_cast在將父類cast到子類時,父類必須要有虛函數一起玩。

?

第一種情況 示例代碼

#includeusing namespace std;class Animal {public:    //父類必須有虛函數	virtual void cry() = 0;};class cat :public Animal {public:	void cry() {		cout << "小貓喵喵喵" << endl;	}};class dog :public Animal {public:	void cry() {		cout << "小狗汪汪汪" << endl;	}};int main() {	dog d1;	Animal* animal = &d1;	cat* ca= dynamic_cast(animal);	if (ca==NULL) {		cout << "這是只狗!" << endl;	}	else {		cout << "這是只貓" << endl;	}	system("pause");	return 0;}

運行結果

?


第二種情況示例代碼

int main() {	dog d1;	Animal& animal = d1;	dog& d2 = dynamic_cast(animal);	system("pause");	return 0;}

這種是沒有任何問題,因為dog與animal是子類與父類的關系,并且animal指針真正指向dog。

但是,如果我們用其他類型接受又會是什么情況呢?


int main() {	dog d1;	Animal& animal = d1;	cat& d2 = dynamic_cast(animal);	system("pause");	return 0;}

基類指針并沒有指向cat,這種情況編譯是沒有任何問題,因為編譯器會認為這是父類與子類之間的轉換,但是當我們運行時,編譯器就會拋出異常?

?

?

對于拋出異常,我們就可以利用try—catch語句捕獲異常,保證程序能繼續運行

int main() {	dog d1;	Animal& animal = d1;	try {		cat& d2 = dynamic_cast(animal);	}	catch (std::bad_cast bc) {		cout << "不是貓,應該是狗" << endl;	}		system("pause");	return 0;}

運行結果

?


5.4.const_cast 轉換

去const屬性。(僅針對于指針和引用)?

?例如

#includeusing namespace std;void demo(const char* p) {	char* p1 = const_cast(p);	p1[0] = "A";}int main() {    //字符數組	char p[] = "1234567";	demo(p);	cout << p << endl;	system("pause");	return 0;}

運行結果

或者直接使用const_cast,運行結果也是一樣

int main() {	char p[] = "1234567";	const_cast(p)[0] = "A";	cout << p << endl;	system("pause");	return 0;}

?但是,對于常量字符串不能去掉const修改

例如

#includeusing namespace std;void demo(const char* p) {	char* p1 = const_cast(p);	p1[0] = "A";}int main() {	const char *p = "1234567";	demo(p);	cout << p << endl;	system("pause");	return 0;}

可以編譯,但是運行會報錯

因為常量所處位置是常量區,內存無法訪問常量區。

?


?5.2 類型轉換使用建議

1)static_cast靜態類型轉換,編譯的時c++編譯器會做編譯時的類型檢查;隱式轉換;

基本類型轉換,父子類之間合理轉換

2)若不同類型之間,進行強制類型轉換,用reinterpret_cast<>() 進行重新解釋

???建 ?議

????????C語言中 ?能隱式類型轉換的,在c++中可用 static_cast<>()進行類型轉換。因C++編譯器在編譯檢查一般都能通過;C語言中不能隱式類型轉換的,在c++中可以用 reinterpret_cast<>() 進行強制類型解釋。

????????總結:static_cast<>()和reinterpret_cast<>() 基本上把C語言中的 強制類型轉換給覆蓋,注意reinterpret_cast<>()很難保證移植性。

3)dynamic_cast<>(),動態類型轉換,安全的虛基類和子類之間轉換;運行時類型檢查

4)const_cast<>(),去除變量的只讀屬性

最后的忠告:程序員必須清楚的知道: 要轉的變量,類型轉換前是什么類型,類型轉換 后是什么類型,轉換后有什么后果。

C++大牛建議一般情況下,不建議進行類型轉換;避免進行類型轉換。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/125067.html

相關文章

  • 近幾個月Github上最熱門的Java項目一覽

    摘要:今天逛了逛,順手精選出了一下近幾個月以來上最熱門的個項目。相關閱讀正式開源,幫助應用快速容器化未來可能會上熱門的項目地址介紹哈哈,皮一下很開心。這是我自己開源的一份文檔,目前仍在完善中,歡迎各位英雄好漢一起完善。 showImg(https://segmentfault.com/img/remote/1460000015766827?w=391&h=220);今天逛了逛Github,順...

    cyqian 評論0 收藏0
  • Apache Flink 1.9 重大特性提前解讀

    showImg(https://segmentfault.com/img/remote/1460000019961426); 今天在 Apache Flink meetup ·北京站進行 Flink 1.9 重大新特性進行了講解,兩位講師分別是 戴資力/楊克特,zhisheng 我也從看完了整個 1.9 特性解讀的直播,預計 Flink 1.9 版本正式發布時間大概是 7 月底 8 月初左右正式發...

    wall2flower 評論0 收藏0
  • 詳解css媒體查詢

    摘要:媒體查詢,添加自,允許內容的呈現針對一個特定范圍的輸出設備而進行裁剪,而不必改變內容本身。而且瀏覽器也不會根據媒體查詢來動態的加載樣式,它只是一股腦的將所有的樣式引入。 簡介 媒體查詢(Media Queries)早在在css2時代就存在,經過css3的洗禮后變得更加強大bootstrap的響應式特性就是從此而來的. 簡單的來講媒體查詢是一種用于修飾css何時起作用的語法. Media...

    leone 評論0 收藏0
  • 詳解css媒體查詢

    摘要:媒體查詢,添加自,允許內容的呈現針對一個特定范圍的輸出設備而進行裁剪,而不必改變內容本身。而且瀏覽器也不會根據媒體查詢來動態的加載樣式,它只是一股腦的將所有的樣式引入。 簡介 媒體查詢(Media Queries)早在在css2時代就存在,經過css3的洗禮后變得更加強大bootstrap的響應式特性就是從此而來的. 簡單的來講媒體查詢是一種用于修飾css何時起作用的語法. Media...

    ymyang 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<