C++特殊類設(shè)計(jì)與類型轉(zhuǎn)換詳細(xì)代碼示例
常見的特殊類的設(shè)計(jì)
1.請(qǐng)?jiān)O(shè)計(jì)一個(gè)類,不能被拷貝
拷貝只會(huì)發(fā)生在兩個(gè)場(chǎng)景中:拷貝構(gòu)造函數(shù)以及賦值運(yùn)算符重載,因此想要讓一個(gè)類禁止拷貝,只需要讓該類不能調(diào)用拷貝構(gòu)造函數(shù)以及賦值運(yùn)算符重載即可。
C++98寫法:
將拷貝構(gòu)造函數(shù)與賦值運(yùn)算符重載只聲明不定義,并且將其訪問(wèn)權(quán)限設(shè)置為私有即可。
class CopyBan
{
//...
private:
CopyBan(const CopyBan& c);
CopyBan& operator=(const CopyBan& c);
//...
};原因:1.設(shè)置成私有:如果只聲明沒有設(shè)置成private,用戶自己如果在類外定義了,就不能禁止拷貝了。
2.只聲明不定義:不定義是因?yàn)樵摵瘮?shù)根本不會(huì)調(diào)用,定義了其實(shí)也沒有什么意義,不寫反而還簡(jiǎn)單,而且如果定義了就不會(huì)防止成員函數(shù)內(nèi)部拷貝了。
C++11寫法:
C++11擴(kuò)展delete的用法,delete除了釋放new申請(qǐng)的資源外,如果在默認(rèn)成員函數(shù)后面跟上=delete,表示讓編譯器刪除掉該默認(rèn)成員函數(shù)。
class CopyBan
{
//...
CopyBan(const CopyBan& c)=delete;
CopyBan& operator=(const CopyBan& c)=delete;
//...
};2.請(qǐng)?jiān)O(shè)計(jì)一個(gè)類,只能在堆上創(chuàng)建對(duì)象
實(shí)現(xiàn)方式:
1.將類的構(gòu)造函數(shù)設(shè)置為私有,拷貝構(gòu)造聲明成私有。防止別人調(diào)用拷貝在棧上生成對(duì)象。
2.提供一個(gè)靜態(tài)的成員函數(shù),在該靜態(tài)成員函數(shù)中完成堆對(duì)象的創(chuàng)建。
class HeapOnly
{
public:
static HeapOnly* CreateHeapObj()
{
return new HeapOnly;
}
private:
HeapOnly()
{ }
//C++98方式
//1.只聲明,不實(shí)現(xiàn)。因?yàn)閷?shí)現(xiàn)可能會(huì)很麻煩,而你本身并不需要
//2.聲明成私有
HeapOnly& operator=(const HeapOnly&);
//C++11方式
HeapOnly& operator=(const HeapOnly&) = delete;
};3.請(qǐng)?jiān)O(shè)計(jì)一個(gè)類,只能在棧上創(chuàng)建對(duì)象
方法:同上述將構(gòu)造函數(shù)私有化,然后設(shè)計(jì)靜態(tài)方法創(chuàng)建對(duì)象返回即可。
class StackOnly
{
public:
static StackOnly CreateStackObj()
{
return StackOnly();
}
//禁掉operator new可以把下面用new 調(diào)用拷貝構(gòu)造申請(qǐng)對(duì)象給禁掉
//StackOnly obj = StackOnly::CreateStackObj();
//StackOnly* ptr = new StackOnly(obj);
void* operator new(size_t size) = delete;
void operator delete(void* p) = delete;
private:
StackOnly()
:_a(0)
{ }
int _a;
};4. 請(qǐng)?jiān)O(shè)計(jì)一個(gè)類,不能被繼承
C++98方式:把類的構(gòu)造函數(shù)私有化,派生類調(diào)不到基類的構(gòu)造函數(shù)就無(wú)法繼承。
C++98中構(gòu)造函數(shù)私有化,派生類中調(diào)不到基類的構(gòu)造函數(shù),則無(wú)法繼承
class NonInherit
{
public:
static NonInherit GetInstance()
{
return NonInherit();
}
private:
NonInherit()
{ }
};C++11方法:final關(guān)鍵字,final修飾類,表示該類不能被繼承。ps(final還能修飾虛函數(shù),表示該虛函數(shù)不能被重寫。)
final 關(guān)鍵字:final修飾類,表示該類不能被繼承。
class A final
{
//..
};5.請(qǐng)?jiān)O(shè)計(jì)一個(gè)類,只能創(chuàng)建一個(gè)對(duì)象(單例模式)
設(shè)計(jì)模式:
設(shè)計(jì)模式(Design Pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過(guò)分類的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。為什么會(huì)產(chǎn)生設(shè)計(jì)模式這樣的東西呢?就像人類歷史發(fā)展會(huì)產(chǎn)生兵法。最開始部落之間打仗時(shí)都是人拼人的對(duì)砍。后來(lái)春秋戰(zhàn)國(guó)時(shí)期,七國(guó)之間經(jīng)常打仗,就發(fā)現(xiàn)打仗也是有套路的,后來(lái)孫子就總結(jié)出了《孫子兵法》。孫子兵法也是類似。
使用設(shè)計(jì)模式的目的:為了代碼可重用性、讓代碼更容易被他人理解、保證代碼可靠性。設(shè)計(jì)模式使代碼編寫真正工程化;設(shè)計(jì)模式是軟件工程的基石脈絡(luò),如同大廈的結(jié)構(gòu)一樣。
單例模式:
一個(gè)類只能創(chuàng)建一個(gè)對(duì)象,即單例模式。該模式可以保證系統(tǒng)中該類只有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn),該實(shí)例被所有程序模塊共享。比如:在某個(gè)服務(wù)器程序中,該服務(wù)器的配置信息存放在一個(gè)文件中,這些配置數(shù)據(jù)由一個(gè)單例對(duì)象統(tǒng)一讀取,然后服務(wù)進(jìn)程中的其他對(duì)象再通過(guò)這個(gè)單例對(duì)象獲取這些配置信息,這種方式簡(jiǎn)化了在復(fù)雜環(huán)境下的配置管理。
單例模式有兩種實(shí)現(xiàn)模式:
1.餓漢模式:
(一開始(main函數(shù)之前)就創(chuàng)建單例對(duì)象)
就是說(shuō)不管你將來(lái)用還是不用,程序啟動(dòng)時(shí)就會(huì)創(chuàng)建一個(gè)唯一的實(shí)例對(duì)象。
餓漢模式
優(yōu)點(diǎn):簡(jiǎn)單
缺點(diǎn):可能會(huì)導(dǎo)致進(jìn)程啟動(dòng)慢,且如果有多個(gè)單例類對(duì)象實(shí)例啟動(dòng)順序不確定。
class Singleton
{
public:
static Singleton* GetInstance()
{
return &m_instance;
}
private:
//構(gòu)造函數(shù)私有化
Singleton(){}
//C++98防止拷貝
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
//or
//C++11
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton m_instance;
};
Singleton Singleton::m_instance;//在程序入口之前就完成單例對(duì)象的初始化但是如果這個(gè)單例對(duì)象再多線程高并發(fā)環(huán)境下頻繁使用,性能要求比較高,那么顯然使用餓漢模式來(lái)避免資源競(jìng)爭(zhēng),提高響應(yīng)速度更好。
2.懶漢模式:
如果單例對(duì)象構(gòu)造十分耗時(shí)或者占用很多資源,比如加載插件啦,初始化網(wǎng)絡(luò)連接啦,讀取文件啦等等,而有可能該對(duì)象程序運(yùn)行時(shí)不會(huì)用到,那么也要在程序一開始就進(jìn)行初始化,就會(huì)導(dǎo)致程序啟動(dòng)時(shí)非常的緩慢。所以這種情況就使用懶漢模式(延遲加載)更好。
懶漢模式也會(huì)有線程安全問(wèn)題,在第一次初始化的時(shí)候要加鎖。
class Singleton
{
public:
static Singleton* GetInstance()
{
注意這里一定要使用Double-Check的方式加鎖,才能保證效率和線程安全
if (nullptr == m_pInstance)
{
m_mtx.lock();//or--- unique_lock<mutex> lock(m_mtx);
if (nullptr == m_pInstance)
{
m_pInstance = new Singleton();
}
m_mtx.unlock();
}
}
//實(shí)現(xiàn)一個(gè)內(nèi)嵌的垃圾回收類
class CGarbo
{
public:
~CGarbo()
{
if (Singleton::m_pInstance)
delete Singleton::m_pInstance;
}
};
//定義一個(gè)靜態(tài)成員變量,程序結(jié)束時(shí),系統(tǒng)自動(dòng)調(diào)用它的析構(gòu)函數(shù)從而釋放單例對(duì)象
static CGarbo Garbo;
main函數(shù)結(jié)束,調(diào)用它的析構(gòu),從而釋放單例對(duì)象
private:
//構(gòu)造函數(shù)私有化
Singleton(){}
//防止拷貝
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton* m_pInstance;//單例對(duì)象指針
static std::mutex m_mtx; //互斥鎖
};
Singleton* Singleton::m_pInstance = nullptr;
Singleton::CGarbo Garbo;
std::mutex Singleton::m_mtx;C++11中創(chuàng)建單例(懶漢模式)最簡(jiǎn)單的方法
class Singleton
{
public:
局部的靜態(tài)對(duì)象,是在第一次調(diào)用時(shí)初始化
static Singleton& GetInstance()
{
static Singleton inst;
return inst;
}
private:
Singleton()
{
std::cout << "Singleton" << std::endl;
}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};C++11之前,這個(gè)代碼是不安全的,編譯器不支持。
C++11之后,可以保證局部靜態(tài)對(duì)象的初始化是線程安全的,只初始化一次。(C++11之后這個(gè)操作變成原子的了。)
C++中的類型轉(zhuǎn)換
1.C語(yǔ)言中的類型轉(zhuǎn)換
在C語(yǔ)言中,如果賦值運(yùn)算符左右兩側(cè)類型不同,或者形參與實(shí)參類型不匹配,或者返回值類型與接收返回值類型不一致時(shí),就需要發(fā)生類型轉(zhuǎn)換,C語(yǔ)言中總共有兩種形式的類型轉(zhuǎn)換:隱式類型轉(zhuǎn)換和顯式類型轉(zhuǎn)換。
1.隱式類型轉(zhuǎn)換:編譯器在編譯階段自動(dòng)進(jìn)行,能轉(zhuǎn)就轉(zhuǎn),不能轉(zhuǎn)就編譯失敗。
2.顯式類型轉(zhuǎn)換:需要用戶自己處理。
void Test()
{
int i = 1;
//隱式類型轉(zhuǎn)換
double d = i;
printf("%d,%.2lf\n", i, d);
int* p = &i;
//顯式類型轉(zhuǎn)換
int address = (int)p;
printf("%x,%d\n", p, address);
}缺陷:轉(zhuǎn)換的可視性比較差,所有的轉(zhuǎn)換形式都是以一種相同形式書寫,難以跟蹤錯(cuò)誤的轉(zhuǎn)換。
2.為什么C++需要四種類型轉(zhuǎn)換
C風(fēng)格的轉(zhuǎn)換形式很簡(jiǎn)單,但是有不少缺點(diǎn):
1.隱式類型轉(zhuǎn)換有些情況下可能會(huì)出問(wèn)題:比如說(shuō)數(shù)據(jù)精度的丟失。
2.顯式類型轉(zhuǎn)換將所有情況混合在一起,代碼不夠清晰。
因此C++提出了自己的類型轉(zhuǎn)換的風(fēng)格,注意C++要兼容C語(yǔ)言,所以在C++中還是可以使用C語(yǔ)言那一套的類型轉(zhuǎn)換。
3.C++強(qiáng)制類型轉(zhuǎn)換
標(biāo)準(zhǔn)C++為了加強(qiáng)類型轉(zhuǎn)換的可視性,引入了四種命名的強(qiáng)制類型轉(zhuǎn)換操作符:
static_cast , reinterpret_cast , const_cast , dynamic_cast
3.1 stacit_cast
static_cast用于非多態(tài)類型的轉(zhuǎn)換(靜態(tài)轉(zhuǎn)換),編譯器隱式執(zhí)行的任何類型轉(zhuǎn)換都可用static_cast,但它不能用于兩個(gè)不相關(guān)的類型進(jìn)行轉(zhuǎn)換。(用于兩個(gè)相關(guān)類型/相近類型之間,C里的隱式類型轉(zhuǎn)換都可用這個(gè)static_cast強(qiáng)轉(zhuǎn)。)
int main()
{
double d = 12.34;
int a = static_cast<int>(d);
std::cout << a << std::endl;
return 0;
}3.2 reinterpret_cast
reinterpret_cast操作符通常為操作數(shù)的位模式提供較低層次的重新解釋,用于將一種類型轉(zhuǎn)換為另一種不同的類型。(可用于兩個(gè)不相關(guān)類型之間進(jìn)行強(qiáng)轉(zhuǎn)。)
int main()
{
double d = 12.34;
int a = static_cast<int>(d);
std::cout << a << std::endl;
這里使用static_cast會(huì)報(bào)錯(cuò),應(yīng)該使用reinterpret
//int* p = static_cast<int*>(a);
int* p = reinterpret_cast<int*>(a);
return 0;
}3.3 const_cast
const_cast最常用的用途就是刪除變量的const屬性,方便賦值。(去掉const屬性。)
int main()
{
const int a = 2;
int* p = const_cast<int*>(&a);
*p = 3;
std::cout << a << std::endl;
return 0;
}3.4 dynamic_cast
dynamic_cast用于將一個(gè)父類對(duì)象的指針/引用轉(zhuǎn)換為子類對(duì)象的指針或引用(動(dòng)態(tài)轉(zhuǎn)換)。
向上轉(zhuǎn)型:子類對(duì)象指針/引用 ->父類指針/引用(不需要轉(zhuǎn)換,賦值兼容規(guī)則)。
向下轉(zhuǎn)型:父類對(duì)象指針/引用->子類指針/引用(用dynamic_cast轉(zhuǎn)型是安全的)。
注意:
1.dynamic_cast只能用于父類含有虛函數(shù)的類。
2.dynamic_cast會(huì)先檢查是否能轉(zhuǎn)換成功,能成功則轉(zhuǎn)換,不能則返回0。
Base* b = new Derived(); b實(shí)際上指向Derived對(duì)象 情況1:成功轉(zhuǎn)換 Derived* d1 = dynamic_cast<Derived*>(b); 成功:b實(shí)際指向Derived對(duì)象,d1是有效的Derived指針 情況2:轉(zhuǎn)換失敗 Base* b2 = new Base(); // b2指向純Base對(duì)象 Derived* d2 = dynamic_cast<Derived*>(b2); 失?。篵2不是Derived對(duì)象,d2 == nullptr
class A
{
public:
virtual void f(){}
};
class B :public A
{};
void fun(A* pa)
{
//dynamic_cast會(huì)先檢查是否能成功轉(zhuǎn)換成功,能成功則轉(zhuǎn)換,不能則返回
B* pb1 = static_cast<B*>(pa);
B* pb2 = dynamic_cast<B*>(pa);
std::cout << "pb1:" << pb1 << std::endl;
std::cout << "pb2:" << pb2 << std::endl;
}
int main()
{
A a;
B b;
fun(&a);
fun(&b);
return 0;
}注意:
強(qiáng)制類型轉(zhuǎn)換關(guān)閉或掛起了正常的類型檢查,每次使用強(qiáng)制類型轉(zhuǎn)換前,程序員應(yīng)該仔細(xì)考慮是否還有其他不同的方法達(dá)到同一目的,如果非強(qiáng)制類型轉(zhuǎn)換不可,則應(yīng)限制強(qiáng)制類型轉(zhuǎn)換值的作用域,以減少發(fā)生錯(cuò)誤的機(jī)會(huì)。強(qiáng)烈建議:避免使用強(qiáng)制類型轉(zhuǎn)換。
4.RTTI(了解)
RTTI:Run-time Type identification的簡(jiǎn)稱,即:運(yùn)行時(shí)類型識(shí)別。
C++通過(guò)一下方式來(lái)支持RTTI:
1.typeid運(yùn)算符。
2.dynamic_cast運(yùn)算符。
3.decltype。
5.常見面試題
1.C++中的四種類型轉(zhuǎn)換分別是:static_cast,reinterpret_cast,const_cast,dynamic_cast。
2.說(shuō)說(shuō)四種類型轉(zhuǎn)換的應(yīng)用場(chǎng)景。

static_cast適用于兩種類型相近的強(qiáng)制轉(zhuǎn)化,dynamic_cast適用于多態(tài)類型的向下轉(zhuǎn)換(安全檢查)(向上轉(zhuǎn)換本來(lái)就是安全的)。cosnt_cast適用于刪除變量的const屬性。reinterpret_cast適用于任意類型之間的轉(zhuǎn)換(危險(xiǎn))。
總結(jié)
到此這篇關(guān)于C++特殊類設(shè)計(jì)與類型轉(zhuǎn)換的文章就介紹到這了,更多相關(guān)C++特殊類設(shè)計(jì)與類型轉(zhuǎn)換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C++四種類型轉(zhuǎn)換全解
- C++ void 指針和指針類型轉(zhuǎn)換方法
- C++中不同類型默認(rèn)轉(zhuǎn)換的規(guī)則和機(jī)制詳解
- C++中五種類型轉(zhuǎn)換的深度對(duì)比與實(shí)踐指南
- C++強(qiáng)制類型轉(zhuǎn)換詳細(xì)示例代碼
- C++特殊類設(shè)計(jì)及類型轉(zhuǎn)換舉例詳解
- C++迭代器和顯示類型轉(zhuǎn)換方式
- 一文帶你探索C++中類型轉(zhuǎn)換的奧秘
- 詳解C++中的四種類型轉(zhuǎn)換運(yùn)算符
- C++類型轉(zhuǎn)換通用接口設(shè)計(jì)實(shí)現(xiàn)
相關(guān)文章
C++數(shù)據(jù)結(jié)構(gòu)之AVL樹的實(shí)現(xiàn)
AVL樹是高度平衡的而二叉樹,它的特點(diǎn)是AVL樹中任何節(jié)點(diǎn)的兩個(gè)子樹的高度最大差別為1,本文主要給大家介紹了C++如何實(shí)現(xiàn)AVL樹,需要的朋友可以參考下2022-06-06
Cocos2d-x學(xué)習(xí)筆記之Hello World源碼分析
這篇文章主要介紹了Cocos2d-x學(xué)習(xí)筆記之Hello World源碼分析,接上一篇內(nèi)容,本文著重分析源碼文件,需要的朋友可以參考下2014-09-09
基于C++實(shí)現(xiàn)日期計(jì)算器的詳細(xì)教程
在現(xiàn)代社會(huì)中,計(jì)算器已經(jīng)進(jìn)入了每一個(gè)家庭,人們?cè)谏詈蛯W(xué)習(xí)中經(jīng)常需要使用到計(jì)算器,下面這篇文章主要給大家介紹了關(guān)于基于C++實(shí)現(xiàn)日期計(jì)算器的相關(guān)資料,需要的朋友可以參考下2022-06-06
帶你用C語(yǔ)言實(shí)現(xiàn)strtok和字符串分割函數(shù)
下面小編就為大家?guī)?lái)一篇c語(yǔ)言中字符串分割函數(shù)及實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2021-09-09
C語(yǔ)言中動(dòng)態(tài)內(nèi)存管理圖文詳解
在編寫程序時(shí),通常并不知道需要處理的數(shù)據(jù)量,或者難以評(píng)估所需處理數(shù)據(jù)量的變動(dòng)程度,下面這篇文章主要給大家介紹了關(guān)于C語(yǔ)言中動(dòng)態(tài)內(nèi)存管理的相關(guān)資料,需要的朋友可以參考下2022-06-06
淺析C++中dynamic_cast和static_cast實(shí)例語(yǔ)法詳解
這篇文章主要介紹了淺析C++中dynamic_cast和static_cast實(shí)例演示,包括static_cast語(yǔ)法知識(shí)和static_cast的作用講解,namic_cast 語(yǔ)法詳解,需要的朋友可以參考下2021-07-07

