幣客bkex是一群外行人做的網(wǎng)站自己如何開網(wǎng)站
=delete
概述?
=delete關(guān)鍵字是c++11新增的關(guān)鍵字,主要用于的場景是:當(dāng)我們不希望類中的函數(shù)被類對象在外部調(diào)用的時候,我們就可以使用這個關(guān)鍵字。
其實,之前我們實現(xiàn)這種功能是將這些函數(shù)放在private修飾符下,但是這種方法是依靠語法特性來實現(xiàn)的,有些地方可能并不合適。
舉個例子:? ?使用private雖然在類外不能使用這些函數(shù)了,但是在類的內(nèi)部還是可以使用的,但是我們目前的要求是在任何地方都不能使用這些函數(shù),那么這時候就得使用=delete關(guān)鍵字了。(因為用來它之后就相當(dāng)于刪除了,自然哪里也用不了了)
疑問:? 那我們不用直接將這些函數(shù)刪除不就好了,為什么多次一舉呢???對于普通的函數(shù),我們直接刪除了自然時最好的,也可以減少歧義。
但是對于類的構(gòu)造函數(shù)呢? 即使我們刪除了,編譯器也會自己給我們創(chuàng)建一個,這樣即使我們刪除掉,最起碼在類內(nèi)部還時可以使用的,所以這時候我們就得使用=delete關(guān)鍵字了。
使用=delete修飾類的構(gòu)造函數(shù)之后,編譯器就不會自動提供了,而且編譯器依然會認(rèn)為它們被刪除了無法使用。
1. 此關(guān)鍵字用于構(gòu)造函數(shù)?
對于構(gòu)造函數(shù),無論隱式的(就是編譯器自己提供的)還是顯示的(我們自己寫的),在創(chuàng)建實例對象的時候,編譯器都會默認(rèn)去調(diào)用這些函數(shù)。但是有些時候,我們并不希望外界使用我們這些函數(shù),那么就可以使用=delete關(guān)鍵字修飾,這樣就相當(dāng)于刪除了對應(yīng)的構(gòu)造函數(shù)。
代碼例子:? ?
c++中有四種構(gòu)造函數(shù): 默認(rèn)構(gòu)造,有參構(gòu)造,拷貝構(gòu)造,賦值構(gòu)造(=運算符重載)
#include <iostream>
#include <stdlib.h>using namespace std;class A {
public:A() = delete;A(const A& a) = delete;A(int a) = delete;A& operator=(const A& a) = delete;
};int main(void) {A a; // 錯誤: 無法引用 "A" 的默認(rèn)構(gòu)造函數(shù) -- 它是已刪除的函數(shù)system("pause");return 0;
}
上面的代碼,我們對類A中的所以構(gòu)造函數(shù)都使用了=delete關(guān)鍵字。我們在main函數(shù)中創(chuàng)建對象a,會報錯,因為創(chuàng)建對象會調(diào)用默認(rèn)構(gòu)造函數(shù),但是我們使用=delete關(guān)鍵字修飾了默認(rèn)構(gòu)造函數(shù),就相當(dāng)于它被刪除了,會報錯。(其它的構(gòu)造函數(shù)也一樣,可以自己嘗試)
一般情況下,我們是不會將所有的構(gòu)造函數(shù)都用=delete(除非你這個類不常見對象),否則,建議只是根據(jù)需要將對應(yīng)的構(gòu)造函數(shù)=delete即可。比如,將拷貝構(gòu)造函數(shù)和復(fù)制構(gòu)造函數(shù)用哪個delete修飾,不允許對類對象進行拷貝了,但是可以使用默認(rèn)構(gòu)造函數(shù)創(chuàng)建對象。(當(dāng)然根據(jù)具體需要來選擇)
2. 此關(guān)鍵字用于普通成員函數(shù)?
其實用于普通成員函數(shù),也是一樣的道理,編譯器會認(rèn)為這個函數(shù)刪除了,但是成員函數(shù)和構(gòu)造函數(shù)不一樣,我們?yōu)槭裁床恢苯訉⑵鋭h除了,反正也不用了,何必多此一舉。
當(dāng)然,有一種情況下也是可以使用的? ?--? 避免傳參時進行形式轉(zhuǎn)換。
一般情況,參數(shù)傳遞的時候,編譯器都會進行隱式轉(zhuǎn)換比如:
#include <iostream>
#include <stdlib.h>using namespace std;class A {
public:void func(int a) {printf("%d\n", a);}
};int main(void) {A a; a.func(1.2); // 打印結(jié)果為1system("pause");return 0;
}
上面,我們給函數(shù)func傳入一個double的值1.2,但是func的參數(shù)類型為int型,所以傳入之后進行了隱式轉(zhuǎn)換,將double的1.2轉(zhuǎn)化為了int的1。
?下面代碼就可以避免這種隱式轉(zhuǎn)換
#include <iostream>
#include <stdlib.h>using namespace std;class A {
public:void func(int a) {printf("%d\n", a);}void func(double a) = delete;
};int main(void) {A a; a.func(1.2); // 出錯system("pause");return 0;
}
其實我們使用函數(shù)重載就可以避免,也就是我們在傳入double的值調(diào)用的是形參為double的函數(shù),這樣就避免了。
但是,如果我們不希望外界使用形參為double的函數(shù),還要避免隱式轉(zhuǎn)換,就可以使用上面這種方式,我們直接傳入double的值,就不會隱式轉(zhuǎn)換而是直接報錯了。
3. 一般情況下,此關(guān)鍵字不要修飾析構(gòu)函數(shù)?
因為如果使用=delete修飾析構(gòu)函數(shù),那么我們創(chuàng)建的對象就無法釋放了。會一直占用空間。因為釋放對象,是需要調(diào)用析構(gòu)函數(shù)的。?
=default?
概述?
default就是默認(rèn)的意思,這個關(guān)鍵字用來修飾構(gòu)造函數(shù),告訴編譯器給函數(shù)實現(xiàn)默認(rèn)的實現(xiàn)。
其實就是給指定函數(shù)實現(xiàn)對應(yīng)默認(rèn)的代碼,適當(dāng)?shù)氖褂每梢蕴岣叽a效率和可讀性。只能用于默認(rèn)構(gòu)造,拷貝構(gòu)造,賦值構(gòu)造和析構(gòu),?-- 因為這些函數(shù)我們不寫,編譯器也會替我們寫(編譯器知道默認(rèn)怎么寫),=default關(guān)鍵字就是讓編譯器替我們寫函數(shù)的實現(xiàn),前提是編譯器知道怎么寫才行。(也就是默認(rèn)構(gòu)造,拷貝構(gòu)造,賦值構(gòu)造和析構(gòu)才行)
當(dāng)然,如果函數(shù)中需要實現(xiàn)我們想要的功能(比如,開辟空間,釋放空間等),或者說有函數(shù)實現(xiàn),就不能使用=default來修飾。
如果在類內(nèi)部給對應(yīng)函數(shù)添加=default,那么其實現(xiàn)的函數(shù)是內(nèi)聯(lián)的,如果不希望是內(nèi)聯(lián)的那就在類外部進行指定=default。
代碼例子:?
class A {
public:A() = default;A(const A& a) = default;A& operator=(const A& a) = default;~A() = default;
};