前言:
類型一直是C++中最重要的部分,相比于其他高級(jí)語言,C++的類型會(huì)復(fù)雜許多,往往一個(gè)類型匹配錯(cuò)誤就會(huì)導(dǎo)致程序報(bào)錯(cuò)。
一、初始化與賦值
定義:初始化與賦值語句是程序中最基本的語句,功能是將某個(gè)值與一個(gè)對(duì)象關(guān)聯(lián)起來;
- 值:字面量、對(duì)象(變量或常量)所表示的值等
- 標(biāo)識(shí)符(對(duì)象):變量、常量、引用
初始化的基本操作:
- 1、在內(nèi)存中開辟空間、保存相應(yīng)的數(shù)值;
- 2、在編譯器中構(gòu)造符號(hào)表、將標(biāo)識(shí)符與相關(guān)內(nèi)存空間關(guān)聯(lián)起來;
二、 類型概述
下面通過幾點(diǎn)概要說明:
1、類型是編譯期概念,可執(zhí)行程序中不存在類型的概念;
2、C++是強(qiáng)類型語言;
強(qiáng)類型語言定義: 一旦一個(gè)變量被定義類型,如果不經(jīng)過強(qiáng)制轉(zhuǎn)換,那么它永遠(yuǎn)就是該數(shù)據(jù)類型;
弱類型語言定義: 某一變量被定義類型,該變量可根據(jù)環(huán)境變化自動(dòng)進(jìn)行轉(zhuǎn)換,不需要強(qiáng)轉(zhuǎn);
3、引入類型是為了更好描述程序,防止誤用;
4、類型描述的信息:
存儲(chǔ)所需要的大小: (sizeof,標(biāo)準(zhǔn)沒有嚴(yán)格限制,根據(jù)硬件不同字節(jié)數(shù)也不同)
取值空間: (可用std::numeric_limits來判斷,超過范圍可能產(chǎn)生溢出)
#include<iostream> #include<limits> int main() { int x = 10; std::cout << std::numeric_limits<int>::min() << std::endl; //-2147483648 std::cout << std::numeric_limits<int>::max() << std::endl; //2147483647 std::cout << std::numeric_limits<unsigned int>::min() << std::endl; //0 std::cout << std::numeric_limits<unsigned int>::max() << std::endl; //4294967295 }
由上面程序運(yùn)行結(jié)果可知,無符號(hào)int類型占4個(gè)字節(jié),也就是32個(gè)比特位,所以最大范圍為232,在不同的硬件下可能不同;
- 對(duì)齊信息(一般存放在內(nèi)存中按類型的對(duì)齊信息的整數(shù)倍存儲(chǔ),比如int的對(duì)齊信息為4個(gè)字節(jié),那存儲(chǔ)的空間首地址為4的倍數(shù),在結(jié)構(gòu)體中,因?yàn)榇嬖趯?duì)齊信息,char也會(huì)按4個(gè)字節(jié)保存)
- 類型可執(zhí)行的操作
三、類型分類
類型可以劃分為基本類型和復(fù)雜類型;
基本(內(nèi)建)類型:C++語言中支持的類型,包含以下幾種:
1、數(shù)值類型
字符類型:char、wchar_t、char16_t、char32_t,通常為1個(gè)字節(jié),表示256個(gè)值,也就是ASCII編碼的字符;
整數(shù)類型:帶符號(hào)整數(shù)類型(short、int、long、long long),無符號(hào)整數(shù)類型(unsigned+帶符號(hào)整數(shù)類型)
浮點(diǎn)類型:float、double、long double
注意:在C++11中引入了固定尺寸的整數(shù)類型,如int32_t等,之前在針對(duì)開發(fā)板的程序中有見過該類型,主要是便于硬件的可移植性:
2、void類型
復(fù)雜類型:由基本類型組合、變種所產(chǎn)生的類型,可能是標(biāo)準(zhǔn)庫引入,或自定義類型;
四、字面值及其類型
字面值:在程序中直接表示為一個(gè)具體數(shù)值或字符串的值;
每個(gè)字面值都有其類型,例子如下:
- 整數(shù)字面值(int):20(十進(jìn)制)、024(八進(jìn)制)、0x14(十六進(jìn)制)
- 浮點(diǎn)數(shù)(double):1.3、1e8
- 字符字面值(char): ‘c'、'\n'
- 字符串字面值(char[4]): “cpp”,注意這里字符串后會(huì)默認(rèn)加/0,所以是四個(gè)字符長度
- 布爾字面值(bool): True、False
像如果想要定義float類型的數(shù),可以加入后綴如1.3f;
C++提供了用戶創(chuàng)建自定義后綴的函數(shù):
#include<iostream> // 后綴可自行定義,我這里用_bang int operator "" _bang(long double x) { return (int)x * 2; } int main() { int x = 7.14_bang; std::cout << x << std::endl; }
上面代碼將7.14的浮點(diǎn)類型轉(zhuǎn)換成整型并增大一倍,可自行定義后綴試一下;
五、變量及其類型
變量:對(duì)應(yīng)一段存儲(chǔ)空間,可以改變其中內(nèi)容;
聲明與定義的區(qū)別:不能重定義已經(jīng)初始化的變量,需要加入extern用來聲明;
初始化:全局變量會(huì)默認(rèn)初始化為0,局部變量會(huì)缺省初始化(隨機(jī)數(shù)值);
六、復(fù)合類型
1、指針:一種間接類型;
如上圖為一個(gè)指針p指向一段內(nèi)存,p保存的為val的地址,我們通過打印尺寸可知,指針p為8個(gè)字節(jié);
特點(diǎn):
- 可以"指向"不同的對(duì)象;
- 具有相同的尺寸;
- 指針與bool的隱式轉(zhuǎn)換:非空指針可以轉(zhuǎn)換為true、空指針可以轉(zhuǎn)換為false;
注意:兩個(gè)符號(hào):*(解引用符)、&(取地址符);
解引用符在不同環(huán)境下含義不同,看如下代碼:
int x = 10; int* p = &x; // 表示p為一個(gè)int指針類型 *p; // 表示解引用,獲取指針指向地址的值
關(guān)于nullptr:
- 一個(gè)特殊的對(duì)象(類型為nullptr_t),表示空指針;
- 類似于C中的NULL,但更加安全;
void 指針*:沒有記錄對(duì)象的尺寸,可以表示任意類型指針,一般作為形參或返回值;
指針對(duì)比對(duì)象:指針復(fù)制成本低,引用成本高;
總結(jié):指針在程序中的作用,最重要的就是作為參數(shù)傳入,由于數(shù)據(jù)類型可能很大,傳入指針大小固定為8個(gè)字節(jié),并且指針值為地址可復(fù)制,復(fù)制成本低,并且可在函數(shù)中改變變量的值;
2、引用
取地址符&也有兩個(gè)含義:
int x = 10; &x; // 取地址符 int& ret = x; // 定義ret為一個(gè)引用類型
特點(diǎn):
- 是對(duì)象的別名,不能綁定字面值(指針也不能指向字面值);
- 構(gòu)造時(shí)綁定對(duì)象,在其生命周期內(nèi)不能綁定其他對(duì)象(賦值操作會(huì)改變對(duì)象內(nèi)容);
- 不存在空引用,但可能存在非法引用,總體比指針安全;
- 屬于編譯期概念,在底層還是通過指針實(shí)現(xiàn);
七、常量類型
- 使用關(guān)鍵字const聲明常量對(duì)象;
- 是編譯期概念,由編譯器保證,作用為防止非法操作、優(yōu)化程序邏輯;
常量指針(頂層常量):
int* const p = &x;
常量指針表示指針為常量,指針不能更改指向;
底層常量:
const int* p = &x;
底層常量表示指針指向的地址的內(nèi)容不能發(fā)生改變,指針指向可改變;
常量引用:
用const int&定義一個(gè)常量引用;
主要用于函數(shù)形參(對(duì)于較復(fù)雜的數(shù)據(jù)類型);
可以綁定字面值;
常量表達(dá)式:
constexpr int x = 1; // x的類型仍為const int
聲明的是編譯期的常量,編譯器可以對(duì)其進(jìn)行優(yōu)化;
八、類型別名
類型別名:引入特殊的含義或便于使用,例如size_t;
引入類型別名的兩種方式:
1、typedef int Mytype;
2、using Mytype = int;(C++11后)
第二種方式更好;
- 應(yīng)將指針類型別名視為一個(gè)整體,引入常量const表示指針為常量的類型;
- 不能通過類型別名構(gòu)造引用的引用;
九、類型自動(dòng)推導(dǎo)
定義:通過初始化表達(dá)式定義對(duì)象類型,編譯器會(huì)自動(dòng)推導(dǎo)得到;(C++11開始)
推導(dǎo)得到的類型還是強(qiáng)類型,并不是弱類型;
自動(dòng)推導(dǎo)的幾種形式:
1、auto:最常用的形式,會(huì)產(chǎn)生類型退化(由于左值右值的類型區(qū)別);
2、const auto、constexpr auto:推導(dǎo)出的是常量、常量表達(dá)式類型;
3、auto&:推導(dǎo)出引用類型,避免類型退化;
4、decltype(exp) :返回exp表達(dá)式的類型(左值加引用);
5、decltype(val) :返回val的類型;
6、decltype(auto) :簡化decltype的使用,C++14開始支持;
補(bǔ)充:類型退化表示一個(gè)變量作為左值和右值時(shí)類型不同,例如數(shù)組作為右值為指針;
十、域與對(duì)象聲明周期
域(scope):表示程序中的一部分,其中的名稱有唯一含義,有全局域、塊域等;
域可以嵌套,嵌套域中定義的名稱可以隱藏外部域中定義的名稱;
對(duì)象的生命周期起始于被初始的時(shí)刻,終止于被銷毀的時(shí)刻;
全局對(duì)象的生命周期是整個(gè)程序運(yùn)行期間,局部對(duì)象終止在所在域執(zhí)行完成;
思考
1、思考下下面關(guān)于指針的兩行代碼的含義
int x = 1; int* p = &x; int y = 0; *p = y; // 第一行 p = &y; // 第二行
這兩行表明了指針的一個(gè)特定,可改變性,每一行的含義如下:
第一行:將指針p指向的內(nèi)存地址的值改變?yōu)閥;
第二行:不改變x的值,而是將指針p的指向改成y;
2、經(jīng)過指針的思考后,我們看看關(guān)于引用的思考
int x = 1; int& f = x; int y = 0; f = y; // 思考一下這一行的作用,是改變了引用f的綁定嗎?
上面這行代碼并不改變f的綁定,而是改變了f的值,同時(shí)引用對(duì)象x的值也發(fā)生改變;
3、經(jīng)過了指針和引用的思考
下面思考下兩者在底層有什么關(guān)聯(lián):
int x; int* p = &x; *p = 1; int& f = x; f = 1;
分析下上面兩行代碼,他們底層實(shí)現(xiàn)會(huì)相同嗎?
這是兩者的匯編代碼實(shí)現(xiàn),可以發(fā)現(xiàn)是完全相同的,引用底層也是通過指針實(shí)現(xiàn)的;
4、思考以下代碼中&x是什么數(shù)據(jù)類型?
int x = 1; const int* p = &x;
如果我們只考慮&x的話,這是一個(gè)int*的類型,但由于第二行代碼執(zhí)行拷貝構(gòu)造,隱式地將&x轉(zhuǎn)換為左值所需要的 const int *類型;
5、思考下面函數(shù)傳參的區(qū)別?
void fun(int x){} void fun(const int& x){}
從本質(zhì)上來說,上面兩種傳參實(shí)現(xiàn)的作用是一致的,第一個(gè)進(jìn)行拷貝構(gòu)造傳遞,所以在函數(shù)內(nèi)部無法改變外部x變量的值,而下面的傳參傳入引用可以在函數(shù)內(nèi)部改變外部x的值,加入const強(qiáng)制成變量;第二種其實(shí)是畫蛇添足地做法,但常量引用對(duì)于復(fù)雜的數(shù)據(jù)類型來說,是能夠節(jié)省很多空間的,比如自定義的結(jié)構(gòu)體;
6、下面常量表示底層常量還是頂層常量?
using mytype = int*; int x = 1; const mytype p = &x;
這里我們?nèi)菀渍`導(dǎo),還會(huì)認(rèn)為這是一個(gè)底層常量,但由于別名的定義,這里其實(shí)是一個(gè)頂層常量,我們可以將mytype看作一個(gè)整體,那么指針的指向不可發(fā)生改變;
7、下面auto&自動(dòng)推導(dǎo)出的y是什么類型?
const int x = 1; auto& y = x;
相信大部分人會(huì)認(rèn)為x會(huì)類型退化,從而y為int&類型,實(shí)際上這里類型不會(huì)退化,所以y為const int&類型;
8、下面來看看decltype自動(dòng)推導(dǎo)的類型是什么?
int x = 1; decltype(x); // 1 decltype((x)); // 2
decltype在傳入?yún)?shù)為左值時(shí)加入引用,那么第一行為一個(gè)變量,所以為int類型,第二行為表達(dá)式,所以加入引用為int&類型;
總結(jié):
本篇講解的類型知識(shí)點(diǎn)很雜,并且涵蓋很多小的知識(shí)點(diǎn),很多細(xì)節(jié)部分在實(shí)際工程中不一定會(huì)接觸到,當(dāng)然在工程中也會(huì)遇到很多自己不理解的類型轉(zhuǎn)換,需要多通過debug模式來查看類型;
本篇知識(shí)點(diǎn)較多,可以選擇自己想了解的部分進(jìn)行查看,后續(xù)會(huì)繼續(xù)推出更深層次的內(nèi)容;
到此這篇關(guān)于C++ 中的類型詳細(xì)的文章就介紹到這了,更多相關(guān)C++ 類型內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://blog.csdn.net/weixin_40620310/article/details/121285344