一文帶你分清C++的定義,聲明和初始化
定義
變量的定義用于為變量分配存儲(chǔ)空間,還可以為變量指定初始值。
int units_sold; double sales_price, avg_price; std::string title; Sales_item curr_book; // class Sales_item
初始化
C++ 支持兩種初始化變量的形式:復(fù)制初始化和直接初始化。復(fù)制初始化語法用等號(hào)(=),直接初始化則是把初始化式放在括號(hào)中。
int ival(1024); // direct-initialization int ival = 1024; // copy-initialization
初始化不是賦值。初始化指創(chuàng)建變量并給它賦初始值,而賦值則是擦除對(duì)象的當(dāng)前值并用新值代替。
當(dāng)定義沒有初始化式的變量時(shí),系統(tǒng)有時(shí)候會(huì)幫我們初始化變量。
1.內(nèi)置類型變量
(Built-in Types,即int,float,double,void,char,bool等。注意string是標(biāo)準(zhǔn)庫定義的類型,不是內(nèi)置類型)
在函數(shù)體外定義的變量都初始化成 0,在函數(shù)體里定義的內(nèi)置類型變量不進(jìn)行自動(dòng)初始化。
2.類
類通過定義一個(gè)或多個(gè)構(gòu)造函數(shù)來控制類對(duì)象的初始化。創(chuàng)建類類型的新對(duì)象,都要執(zhí)行構(gòu)造函數(shù),保證每個(gè)對(duì)象的數(shù)據(jù)成員具有合適的初始值。
構(gòu)造函數(shù)可以包含一個(gè)構(gòu)造函數(shù)初始化列表,以一個(gè)冒號(hào)開始,接著是一個(gè)以逗號(hào)分隔的數(shù)據(jù)成員列表,每個(gè)數(shù)據(jù)成員后面跟一個(gè)放在圓括號(hào)中的初始化式。與任意的成員函數(shù)一樣,構(gòu)造函數(shù)可以定義在類的內(nèi)部或外部。
構(gòu)造函數(shù)初始化只在構(gòu)造函數(shù)的定義中而不是聲明中指定。
//將 isbn 成員初始化為 book 形參的值,將 units_sold 和 revenue 初始化為 0。 Sales_item::Sales_item(const string &book): isbn(book), units_sold(0), revenue(0.0) { }
如果沒有提供初始化式,那么就會(huì)使用默認(rèn)構(gòu)造函數(shù)。如果類具有默認(rèn)構(gòu)造函數(shù),那么就可以在定義該類的變量時(shí)不用顯式地初始化變量。例如,string 類定義了默認(rèn)構(gòu)造函數(shù)來初始化 string 變量為空字符串。
string a; cout << "a: " << a <<endl;
輸出:
a:
此外,省略初始化列表在構(gòu)造函數(shù)的函數(shù)體內(nèi)對(duì)數(shù)據(jù)成員賦值是合法的。
Sales_item::Sales_item(const string &book) { isbn = book; units_sold = 0; revenue = 0.0; }
不管成員是否在構(gòu)造函數(shù)初始化列表中顯式初始化,類類型的數(shù)據(jù)成員總是在初始化階段初始化。初始化發(fā)生在計(jì)算階段開始之前。(也就是函數(shù)體執(zhí)行以前)→ 這里似乎有些難以理解,通過后文的實(shí)例也許你能明白
在構(gòu)造函數(shù)初始化列表中沒有顯式提及的每個(gè)成員,使用與初始化變量相同的規(guī)則來進(jìn)行初始化。運(yùn)行該類型的默認(rèn)構(gòu)造函數(shù),來初始化類類型的數(shù)據(jù)成員。內(nèi)置或復(fù)合類型的成員的初始值依賴于對(duì)象的作用域:在局部作用域中這些成員不被初始化,而在全局作用域中它們被初始化為 0。
未初始化的變量
局部作用域的內(nèi)置類型變量將不被自動(dòng)初始化,這可能導(dǎo)致其成為未初始化的變量。這是常見的程序錯(cuò)誤,但編譯器無法檢測(cè)出所有未初始化變量的使用。→ 你肯定可以理解這可能導(dǎo)致的災(zāi)難性后果了(這竟然不可以運(yùn)行,為什么呢?這竟然可以運(yùn)行,為什么呢?.jpg)再稍微解釋一下原因:?jiǎn)栴}出在未初始化的變量事實(shí)上都有一個(gè)值。編譯器把該變量放到內(nèi)存中的某個(gè)位置,而把這個(gè)位置的無論哪種位模式都當(dāng)成是變量初始的狀態(tài)。當(dāng)被解釋成整型值時(shí),任何位模式都是合法的值——雖然這個(gè)值不可能是程序員想要的。因?yàn)檫@個(gè)值合法,所以使用它也不可能會(huì)導(dǎo)致程序崩潰??赡艿慕Y(jié)果是導(dǎo)致程序錯(cuò)誤執(zhí)行和/或錯(cuò)誤計(jì)算。
聲明
聲明用于向程序表明變量的類型和名字。定義也是聲明:當(dāng)定義變量時(shí)我們聲明了它的類型和名字。
可以通過使用extern關(guān)鍵字聲明變量名而不定義它。extern 聲明不是定義,也不分配存儲(chǔ)空間。事實(shí)上,它只是說明變量定義在程序的其他地方。程序中變量可以聲明多次,但只能定義一次。
extern int i; // declares but does not define i int i; // declares and defines i
只有當(dāng)聲明也是定義時(shí),聲明才可以有初始化式,因?yàn)橹挥卸x才分配存儲(chǔ)空間。初始化式必須要有存儲(chǔ)空間來進(jìn)行初始化。如果聲明有初始化式,那么它可被當(dāng)作是定義,即使聲明標(biāo)記為 extern:
extern int i = 10; //defines i
在 C++ 語言中,變量必須且僅能定義一次,而且在使用變量之前必須定義或聲明變量。
實(shí)例
#include <iostream> #include <string> using namespace std; //類x的聲明 //如果這一部分放在main()函數(shù)后面,報(bào)錯(cuò):error: 'x' was not declared in this scope //在實(shí)際工程中,這部分聲明將放在頭文件(.h)中,而構(gòu)造函數(shù)及成員函數(shù)的定義則放在.cpp文件中 class x{ public: x(int a, int b, string c); void print_data(); private: //類數(shù)據(jù)成員的變量名最好在開頭加一個(gè)字母m(即member) int ma; int mb; string mc; }; int main(){ int a1(2); //直接初始化 int b1 = 3; //復(fù)制初始化 string c1; //默認(rèn)構(gòu)造函數(shù)初始化string變量為空字符串 c1 = "dwkw"; //賦值 x data(a1, b1, c1); //調(diào)用構(gòu)造函數(shù)初始化 return 0; print_data(); } //構(gòu)造函數(shù)定義 x::x(int a, int b, string c):ma(a), mb(b), mc(c){} //成員函數(shù)定義 void x::print_data(){ cout << "ma: " << ma << endl; cout << "mb: " << mb << endl; cout << "mc: " << mc << endl; }
輸出:
ma: 2
mb: 3
mc: dwkw
聲明時(shí)提供初值
如果在類的聲明中就對(duì)數(shù)據(jù)成員提供初值,而不在初始化列表中提供,程序可以執(zhí)行,輸出ma的值為1。
class x{ public: x(int a, int b, string c); void print_data(); private: int ma = 1; //聲明時(shí)提供初值 int mb; string mc; }; //去掉初始化列表 x::x(int a, int b, string c):mb(b), mc(c){}
這一做法在早期版本不予支持,但從c++11就可以了。[2]
不過這破壞了類的抽象性,并不建議這樣做。
查看c++版本的方法:[3]
cout << __cplusplus << endl; //輸出c++版本
在構(gòu)造函數(shù)內(nèi)賦初值,而不用列表
前面提到省略初始化列表在構(gòu)造函數(shù)的函數(shù)體內(nèi)對(duì)數(shù)據(jù)成員賦值是合法的。
//去掉初始化列表,在構(gòu)造函數(shù)體內(nèi)賦值 //其它代碼保持不變 x::x(int a, int b, string c){ cout << "賦值前: " << endl; print_data(); cout << "賦值后: " << endl; ma = 4; mb = 5; mc = "ser"; }
輸出:
賦值前:
ma: 4199744
mb: 0
mc:
賦值后:
ma: 4
mb: 5
mc: ser
實(shí)際上我就沒寫初始化列表,但系統(tǒng)它就會(huì)在這里執(zhí)行初始化??傊蜁?huì)在執(zhí)行構(gòu)造函數(shù)體內(nèi)的語句之前初始化(如果它可以自動(dòng)初始化),即使根本沒寫初始化列表。→ 嘖,我就像在說繞口令,希望你能明白我的意思
但是ma和mb都是局部作用域(我不確定類作用域是否是局部作用域,但從輸出來看,ma不是0,所以應(yīng)該沒有能夠初始化)的內(nèi)置類型變量,不進(jìn)行自動(dòng)初始化;mc有默認(rèn)構(gòu)造函數(shù),自動(dòng)初始化為空字符串。
而后,執(zhí)行構(gòu)造函數(shù)體內(nèi)部的語句,將對(duì)ma和mb進(jìn)行初始化(我想這里應(yīng)該是初始化而不是賦值),對(duì)mc賦值。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
數(shù)據(jù)結(jié)構(gòu)之堆的具體使用
本文主要介紹了數(shù)據(jù)結(jié)構(gòu)之堆的具體使用,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02C++實(shí)現(xiàn)LeetCode(161.一個(gè)編輯距離)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(161.一個(gè)編輯距離),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07c語言求出給定范圍內(nèi)的所有質(zhì)數(shù)
本文主要介紹了c語言求出給定范圍內(nèi)的所有質(zhì)數(shù)的小程序。具有很好的參考價(jià)值。下面跟著小編一起來看下吧2017-04-04Linux環(huán)境g++編譯GDAL動(dòng)態(tài)庫操作方法
下面小編就為大家?guī)硪黄狶inux環(huán)境g++編譯GDAL動(dòng)態(tài)庫操作方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05Qt實(shí)現(xiàn)實(shí)時(shí)鼠標(biāo)繪制圖形
這篇文章主要介紹了Qt中QGraphicsView架構(gòu)下如何實(shí)現(xiàn)實(shí)時(shí)鼠標(biāo)繪制圖形,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起動(dòng)手試一試2022-02-02Linux C 時(shí)間函數(shù)應(yīng)用
本文是關(guān)于Linux C時(shí)間函數(shù) time_t struct tm 進(jìn)行了詳細(xì)的分析介紹并有應(yīng)用實(shí)例,希望能幫到有需要的同學(xué)2016-07-07