C++特殊類設(shè)計及類型轉(zhuǎn)換舉例詳解
一、設(shè)計一個不能被拷貝的類
拷貝只會發(fā)生在兩個場景中:拷貝構(gòu)造函數(shù)以及賦值運算符重載,因此想要讓一個類禁止拷貝, 只需讓該類不能調(diào)用拷貝構(gòu)造函數(shù)以及賦值運算符重載即可。
C++98:
將拷貝構(gòu)造函數(shù)與賦值運算符重載只聲明不定義,并且將其訪問權(quán)限設(shè)置為私有即可。
原因:
- 設(shè)置成私有:如果只聲明沒有設(shè)置成private,用戶自己如果在類外定義了,就可以不被禁止拷貝了
- 只聲明不定義:不定義是因為該函數(shù)根本不會調(diào)用,定義了其實也沒有什么意義,不寫反而還簡單,而且如果定義了就不會防止成員函數(shù)內(nèi)部拷貝了。
示例代碼:
class CopyBan
{
private:
CopyBan(const CopyBan&);
CopyBan& operator=(const CopyBan&);
//...
};C++11:
C++11擴展delete的用法,delete除了釋放new申請的資源外,如果在默認成員函數(shù)后跟上
=delete,表示讓編譯器刪除掉該默認成員函數(shù)。
示例代碼:
class CopyBan
{
// ...
CopyBan(const CopyBan&) = delete;
CopyBan& operator=(const CopyBan&) = delete;
//...
};二、設(shè)計一個只能在堆上創(chuàng)建對象的類
實現(xiàn)方式:
1. 將類的構(gòu)造函數(shù)私有,拷貝構(gòu)造聲明成私有。防止別人調(diào)用拷貝在棧上生成對象。
2. 提供一個靜態(tài)的成員函數(shù),在該靜態(tài)成員函數(shù)中完成堆對象的創(chuàng)建
方法一:
class HeapOnly
{
public:
//提供在堆上創(chuàng)建對象的方法
static HeapOnly* CreateObj()
{
return new HeapOnly;
}
//將拷貝構(gòu)造和賦值重載也禁止
HeapOnly(const HeapOnly&) = delete;
HeapOnly& operator=(const HeapOnly&) = delete;
private:
//將構(gòu)造私有,防止外界直接創(chuàng)建對象
HeapOnly()
{}
};
int main()
{
//靜態(tài)區(qū)上創(chuàng)建對象
//static HeapOnly hp0;
// 棧上創(chuàng)建對象
//HeapOnly hp1;
//堆上創(chuàng)建對象
//HeapOnly* hp2 = new HeapOnly;
HeapOnly* hp3 = HeapOnly::CreateObj();
//要防止別人通過這種方式在棧上創(chuàng)建對象
//通過禁止拷貝構(gòu)造來防止這種方式
//HeapOnly hp4(*hp3);
//手動釋放堆上的資源
delete hp3;
return 0;
}解釋:上面代碼是通過私有構(gòu)造函數(shù)的方式來阻止外界自己創(chuàng)建對象,并提供一個在堆上創(chuàng)建對象的方法,使得外界只能在堆上創(chuàng)建對象,將拷貝構(gòu)造和賦值重載禁止是防止別人像圖中那樣通過這兩個方法在棧上創(chuàng)建對象。
方法二:
class HeapOnly
{
public:
void Destroy()
{
delete this;
}
private:
//析構(gòu)函數(shù)私有化
~HeapOnly()
{}
};
int main()
{
//static HeapOnly hp0;
//HeapOnly hp1;
HeapOnly* hp2 = new HeapOnly;
//delete hp2;
hp2->Destroy();
return 0;
}解釋:該方法是通過私有析構(gòu)函數(shù)的方式使外界無法自動調(diào)用析構(gòu)函數(shù),進而無法創(chuàng)建對象,只能在堆上創(chuàng)建對象,因為在堆上申請的空間需要自己主動釋放,不會自動調(diào)用析構(gòu)。這種實現(xiàn)的方法無需禁止拷貝構(gòu)造和賦值重載,因為通過這兩種方式創(chuàng)建出來的棧上的對象仍會因為無法調(diào)用析構(gòu)而無法創(chuàng)建。
三、設(shè)計一個只能在棧上創(chuàng)建對象的類
方法一:同上將構(gòu)造函數(shù)私有化,然后設(shè)計靜態(tài)方法創(chuàng)建對象返回,并禁止掉重載的new和delete。
class StackOnly
{
public:
static StackOnly CreateObj()
{
return StackOnly();
}
//StackOnly(const StackOnly& s) = delete;
void* operator new(size_t size) = delete;
void operator delete(void* p) = delete;
private:
StackOnly()
:_a(0)
{}
private:
int _a;
};
int main()
{
//static StackOnly s1;
//StackOnly s2;
//StackOnly* s3 = new StackOnly;
StackOnly s4 = StackOnly::CreateObj();
//StackOnly* s5 = new StackOnly(s4);
static StackOnly s6(s4);
return 0;
}解釋:私有構(gòu)造函數(shù),并提供創(chuàng)建對象的方法,這樣外界無法自己創(chuàng)建對象,只能使用提供的方法在棧上創(chuàng)建對象。但如果只是這樣外界可以通過拷貝構(gòu)造在堆上或在靜態(tài)區(qū)創(chuàng)建對象,可我們不能禁止掉拷貝構(gòu)造,因為在棧上創(chuàng)建對象并返回,會用到拷貝構(gòu)造,如上述代碼中s4接收返回的棧上的對象就是將棧上的對象拷貝給s4的,所以我們重載new和delete,C++中如果我們重載了這兩個方法,那么我們調(diào)用這兩個方法時會優(yōu)先調(diào)用我們自己的而不是庫的,我們再將這兩個方法禁止,這樣就阻止別人在堆上創(chuàng)建對象了。但是在靜態(tài)區(qū)禁止不了。
方法二:同上將構(gòu)造函數(shù)私有化,然后設(shè)計靜態(tài)方法創(chuàng)建對象返回,并禁止掉拷貝構(gòu)造,但提供移動構(gòu)造。
class StackOnly
{
public:
static StackOnly CreateObj()
{
return StackOnly();
}
StackOnly(const StackOnly&& s)
{
//......
}
StackOnly(const StackOnly& s) = delete;
private:
StackOnly()
:_a(0)
{}
private:
int _a;
};
int main()
{
StackOnly s4 = StackOnly::CreateObj();
//StackOnly* s5 = new StackOnly(s4);
//static StackOnly s6(s4);
//這種方式禁止不掉
StackOnly* s5 = new StackOnly(move(s4));
static StackOnly s6(move(s4));
return 0;
}解釋:提供的在棧上創(chuàng)建對象的方法返回的是匿名對象,是右值,可以通過移動構(gòu)造賦值出去,這樣外界用事先創(chuàng)建好的對象再通過拷貝的方式在堆上或者在靜態(tài)區(qū)創(chuàng)建對象就創(chuàng)建不了了,但如果有人將左值move成右值再去拷貝,那就阻止不了了。
四、設(shè)計一個不能被繼承的類
C++98方式:構(gòu)造函數(shù)私有化,派生類中調(diào)不到基類的構(gòu)造函數(shù)。則無法繼承
示例代碼:
// C++98中構(gòu)造函數(shù)私有化,派生類中調(diào)不到基類的構(gòu)造函數(shù)。則無法繼承
class NonInherit
{
public:
static NonInherit GetInstance()
{
return NonInherit();
}
private:
NonInherit()
{}
};C++11方法:?nal關(guān)鍵字,?nal修飾類,表示該類不能被繼承。
示例代碼:
class A final
{
// ....
};五、設(shè)計一個只能創(chuàng)建一個對象的類(單例模式)
設(shè)計模式:
設(shè)計模式(Design Pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類的、代碼設(shè)計經(jīng)驗的 總結(jié)。為什么會產(chǎn)生設(shè)計模式這樣的東西呢?就像人類歷史發(fā)展會產(chǎn)生兵法。最開始部落之間打 仗時都是人拼人的對砍。后來春秋戰(zhàn)國時期,七國之間經(jīng)常打仗,就發(fā)現(xiàn)打仗也是有套路的,后 來孫子就總結(jié)出了《孫子兵法》。孫子兵法也是類似。
使用設(shè)計模式的目的:為了代碼可重用性、讓代碼更容易被他人理解、保證代碼可靠性。 設(shè)計模 式使代碼編寫真正工程化;設(shè)計模式是軟件工程的基石脈絡(luò),如同大廈的結(jié)構(gòu)一樣。
單例模式:
一個類只能創(chuàng)建一個對象,即單例模式,該模式可以保證系統(tǒng)中該類只有一個實例,并提供一個 訪問它的全局訪問點,該實例被所有程序模塊共享。比如在某個服務(wù)器程序中,該服務(wù)器的配置 信息存放在一個文件中,這些配置數(shù)據(jù)由一個單例對象統(tǒng)一讀取,然后服務(wù)進程中的其他對象再 通過這個單例對象獲取這些配置信息,這種方式簡化了在復(fù)雜環(huán)境下的配置管理。
單例模式有兩種實現(xiàn)模式:
- 餓漢模式
就是說不管你將來用不用,程序啟動時就創(chuàng)建一個唯一的實例對象。
// 餓漢模式
// 1、多個餓漢模式的單例,某個對象初始化內(nèi)容較多(讀文件),會導(dǎo)致程序啟動慢
// 2、A和B兩個餓漢,對象初始化存在依賴關(guān)系,要求A先初始化,B再初始化,餓漢無法保證
class InfoMgr
{
public:
static InfoMgr& GetInstance()
{
return _ins;
}
void Print()
{
cout << _ip << endl;
cout << _port << endl;
cout << _buffSize << endl;
}
private:
InfoMgr(const InfoMgr&) = delete;
InfoMgr& operator=(const InfoMgr&) = delete;
InfoMgr()
{
cout << "InfoMgr()" << endl;
}
private:
string _ip = "127.0.0.1";
int _port = 80;
size_t _buffSize = 1024 * 1024;
//...
static InfoMgr _ins;
};
InfoMgr InfoMgr::_ins;
int main()
{
InfoMgr::GetInstance().Print();
//InfoMgr copy(InfoMgr::GetInstance());
return 0;
}
解釋:首先單例模式只允許一個類創(chuàng)建一個對象,所以還是將構(gòu)造函數(shù),拷貝構(gòu)造,賦值重載全部禁掉,防止外界自己創(chuàng)建對象,然后再類里面添加一個私有的靜態(tài)的類的對象,這個對象因為是靜態(tài)的,不會存在類中,存在靜態(tài)區(qū),所以不會造成類里面有類對象,類對象里面又有類對象這種無窮套娃的問題,這里將該類的對象放到類中是為了讓它受到類域的限制,不讓外界隨意訪問,其實就相當于靜態(tài)的全局變量(但被類域限制著),當程序一啟動,這個對象就會被創(chuàng)建,我們再提供一個方法供外界獲取這個對象即可。
注意點:首先,多個餓漢模式的單例,某個對象初始化內(nèi)容較多(如需要讀文件),會導(dǎo)致程序啟動慢。其次,A和B兩個餓漢,對象初始化存在依賴關(guān)系,要求A先初始化,B再初始化,餓漢無法保證,因為都是全局變量,誰先初始化無法保證。
如果這個單例對象在多線程高并發(fā)環(huán)境下頻繁使用,性能要求較高,那么顯然使用餓漢模式來避 免資源競爭,提高響應(yīng)速度更好。
- 懶漢模式
如果單例對象構(gòu)造十分耗時或者占用很多資源,比如加載插件啊, 初始化網(wǎng)絡(luò)連接啊,讀取文件啊等等,而有可能該對象程序運行時不會用到,那么也要在程序一開始就進行初始化, 就會導(dǎo)致程序啟動時非常的緩慢。 所以這種情況使用懶漢模式(延遲加載)更好。
// 懶漢模式
class InfoMgr
{
public:
static InfoMgr& GetInstance()
{
// 第一次調(diào)用時創(chuàng)建單例對象
// 有線程安全的風(fēng)險
if (_pins == nullptr)
{
_pins = new InfoMgr;
}
return *_pins;
}
void Print()
{
cout << _ip << endl;
cout << _port << endl;
cout << _buffSize << endl;
}
static void DelInstance()
{
delete _pins;
_pins = nullptr;
}
private:
InfoMgr(const InfoMgr&) = delete;
InfoMgr& operator=(const InfoMgr&) = delete;
InfoMgr()
{
cout << "InfoMgr()" << endl;
}
private:
string _ip = "127.0.0.1";
int _port = 80;
size_t _buffSize = 1024 * 1024;
//...
static InfoMgr* _pins;
};
InfoMgr* InfoMgr::_pins = nullptr;
int main()
{
InfoMgr::GetInstance().Print();
InfoMgr::GetInstance().Print();
return 0;
}解釋:和餓漢思路類似,只不過懶漢不能一開始就創(chuàng)建好這個唯一的類對象,只有當需要的時候才會創(chuàng)建,不過這里懶漢的對象是在堆上創(chuàng)建的,可以對外提供一個釋放資源的方法。
注意點:懶漢模式創(chuàng)建對象時有線程風(fēng)險問題,這里只是演示一下基本思路,所以代碼并沒有做的非常嚴謹,如果想解決這個問題可以加鎖。
方法二:(此方法適用C++11之后)
class InfoMgr
{
public:
static InfoMgr& GetInstance()
{
// 第一次調(diào)用時創(chuàng)建單例對象
// C++11之后
static InfoMgr ins;
return ins;
}
void Print()
{
cout << _ip << endl;
cout << _port << endl;
cout << _buffSize << endl;
}
private:
InfoMgr(const InfoMgr&) = delete;
InfoMgr& operator=(const InfoMgr&) = delete;
InfoMgr()
{
cout << "InfoMgr()" << endl;
}
private:
string _ip = "127.0.0.1";
int _port = 80;
size_t _buffSize = 1024 * 1024;
//...
};
int main()
{
InfoMgr::GetInstance().Print();
InfoMgr::GetInstance().Print();
cout << &InfoMgr::GetInstance() << endl;
cout << &InfoMgr::GetInstance() << endl;
return 0;
}解釋:這里提供一個局部的靜態(tài)變量,而不是全局的,這樣只有第一次需要的時候才會創(chuàng)建,后面因為是靜態(tài)變量,再去申請對象時使用的是前面創(chuàng)建好的靜態(tài)對象。
六、C語言中的類型轉(zhuǎn)換
在C語言中,如果賦值運算符左右兩側(cè)類型不同,或者形參與實參類型不匹配,或者返回值類型與 接收返回值類型不一致時,就需要發(fā)生類型轉(zhuǎn)化,C語言中總共有兩種形式的類型轉(zhuǎn)換:隱式類型 轉(zhuǎn)換和顯式類型轉(zhuǎn)換。
- 隱式類型轉(zhuǎn)化:編譯器在編譯階段自動進行,能轉(zhuǎn)就轉(zhuǎn),不能轉(zhuǎn)就編譯失敗
- 顯式類型轉(zhuǎn)化:需要用戶自己處理
缺陷:轉(zhuǎn)換的可視性比較差,所有的轉(zhuǎn)換形式都是以一種相同形式書寫,難以跟蹤錯誤的轉(zhuǎn)換。
七、C++中的三類類型轉(zhuǎn)換
內(nèi)置類型之間:
- 隱式類型轉(zhuǎn)換 整形之間/整形和浮點數(shù)之間
- 顯示類型的轉(zhuǎn)換 指針和整形、指針之間
示例代碼:
// a、內(nèi)置類型之間
// 1、隱式類型轉(zhuǎn)換 整形之間/整形和浮點數(shù)之間
// 2、顯示類型的轉(zhuǎn)換 指針和整形、指針之間
int main()
{
int i = 1;
// 隱式類型轉(zhuǎn)換
double d = i;
printf("%d, %.2f\n", i, d);
int* p = &i;
// 顯示的強制類型轉(zhuǎn)換
int address = (int)p;
printf("%p, %d\n", p, address);
return 0;
}內(nèi)置類型和自定義類型之間:
- 自定義類型 = 內(nèi)置類型 ->構(gòu)造函數(shù)支持
- 內(nèi)置類型 = 自定義類型 ->operator重載支持
示例代碼:
// b、內(nèi)置類型和自定義類型之間
// 1、自定義類型 = 內(nèi)置類型 ->構(gòu)造函數(shù)支持
// 2、內(nèi)置類型 = 自定義類型
class A
{
public:
//explicit A(int a) //explicit關(guān)鍵字可以禁止隱式轉(zhuǎn)換,必須顯示轉(zhuǎn)換
A(int a)
:_a1(a)
,_a2(a)
{}
A(int a1, int a2)
:_a1(a1)
, _a2(a2)
{}
//自定義類型 -> 內(nèi)置類型
// ()被仿函數(shù)占用了,不能用
// operator 類型實現(xiàn),有返回值,無返回類型
// 默認返回類型就是要轉(zhuǎn)換的類型
//explicit operator int()
operator int()
{
return _a1 + _a2;
}
private:
int _a1 = 1;
int _a2 = 1;
};
int main()
{
//內(nèi)置類型轉(zhuǎn)換自定義類型
string s1 = "1111111";
A aa1 = 1;
//A aa1 = (A)1;
A aa2 = { 2,2 };
const A& aa3 = { 2,2 };
//自定義類型轉(zhuǎn)換內(nèi)置類型
int z = aa1.operator int();
//int x = (int)aa1;
int x = aa1;
int y = aa2;
cout << x << endl;
cout << y << endl;
//庫里的shared_ptr提供了轉(zhuǎn)換為bool類型的重載函數(shù)
std::shared_ptr<int> foo;
std::shared_ptr<int> bar(new int(34));
//這里本質(zhì)是轉(zhuǎn)換為了bool類型
//if (foo.operator bool())
if (foo)
std::cout << "foo points to " << *foo << '\n';
else
std::cout << "foo is null\n";
if (bar)
std::cout << "bar points to " << *bar << '\n';
else
std::cout << "bar is null\n";
return 0;
}
自定義類型和自定義類型之間:
- 對應(yīng)的構(gòu)造函數(shù)支持
示例代碼:
// c、自定義類型和自定義類型之間 -- 對應(yīng)的構(gòu)造函數(shù)支持
class A
{
public:
A(int a)
:_a1(a)
, _a2(a)
{}
A(int a1, int a2)
:_a1(a1)
, _a2(a2)
{}
int get() const
{
return _a1 + _a2;
}
private:
int _a1 = 1;
int _a2 = 1;
};
class B
{
public:
B(int b)
:_b1(b)
{}
B(const A& aa)
:_b1(aa.get())
{}
private:
int _b1 = 1;
};
#include"List.h"
#include<list>
int main()
{
A aa1(1);
B bb1(2);
bb1 = aa1;
B& ref1= bb1;
const B& ref2 = aa1;
bit::list<int> lt = { 1,2,3,4 };
// 權(quán)限的縮小?權(quán)限縮小和放大,僅限于const的指針和引用
// 不是權(quán)限縮小,這里類型轉(zhuǎn)換
bit::list<int>::const_iterator cit = lt.begin();
while (cit != lt.end())
{
cout << *cit << " ";
++cit;
}
cout << endl;
return 0;
}解釋:上面代碼中涉及到一個從普通迭代器到const迭代器的轉(zhuǎn)換問題,這不屬于權(quán)限縮小,權(quán)限問題只有在指針和引用中存在,這里無法轉(zhuǎn)換是因為迭代器的實現(xiàn)使用了模版,模版實例化后普通迭代器和const迭代器本就是不同的類型,所以這里是類型不同導(dǎo)致相互之間無法賦值,解決辦法如下圖。

解釋:我們需要再迭代器中增加一個方法,這個方法的形參必須是普通迭代器類型,當該迭代器模版實例化為普通迭代器后,這個函數(shù)在普通迭代器中就是拷貝構(gòu)造,當該迭代器模板實例化為const迭代器后,這個函數(shù)在const迭代器中就能夠?qū)魅氲钠胀ǖ鬓D(zhuǎn)換為const迭代器。
八、C++強制類型轉(zhuǎn)換
8.1、為什么C++需要四種類型轉(zhuǎn)換
C風(fēng)格的轉(zhuǎn)換格式很簡單,但是是有不少缺點的:
- 隱式類型轉(zhuǎn)化有些情況下可能會出問題:比如數(shù)據(jù)精度丟失
- 顯式類型轉(zhuǎn)換將所有情況混合在一起,代碼不夠清晰
因此C++提出了自己的類型轉(zhuǎn)化風(fēng)格,注意因為C++要兼容C語言,所以C++中還可以使用C語言的 轉(zhuǎn)化風(fēng)格。標準C++為了加強類型轉(zhuǎn)換的可視性,引入了四種命名的強制類型轉(zhuǎn)換操作符:
- static_cast
- reinterpret_cast
- const_cast
- dynamic_cast
8.2、static_cast
static_cast用于非多態(tài)類型的轉(zhuǎn)換(靜態(tài)轉(zhuǎn)換),編譯器隱式執(zhí)行的任何類型轉(zhuǎn)換都可用。但它不能用于兩個不相關(guān)的類型進行轉(zhuǎn)換。(即static_cast對應(yīng)隱式類型轉(zhuǎn)換)
示例代碼:
int main()
{
// 對應(yīng)隱式類型轉(zhuǎn)換 -- 數(shù)據(jù)的意義沒有改變
double d = 12.34;
int a = static_cast<int>(d);
cout << a << endl;
return 0;
}
8.3、reinterpret_cast
reinterpret_cast操作符通常為操作數(shù)的位模式提供較低層次的重新解釋,用于將一種類型轉(zhuǎn)換為另一種不同的類型。(即reinterpret_cast對應(yīng)強制類型轉(zhuǎn)換)
示例代碼:
int main()
{
// 對應(yīng)隱式類型轉(zhuǎn)換 -- 數(shù)據(jù)的意義沒有改變
double d = 12.34;
int a = static_cast<int>(d);
cout << a << endl;
// 對應(yīng)強制類型轉(zhuǎn)換 -- 數(shù)據(jù)的意義已經(jīng)發(fā)生改變
int* p1 = reinterpret_cast<int*>(a);;
return 0;
}8.4、const_cast
const_cast最常用的用途就是刪除變量的const屬性,方便賦值。
示例代碼:
int main()
{
// 對應(yīng)強制類型轉(zhuǎn)換中有風(fēng)險的去掉const屬性
//volatile const int b = 2;
const int b = 2;
int* p2 = const_cast<int*>(&b);
*p2 = 3;
cout << b << endl;
cout << *p2 << endl;
return 0;
}解釋:上面代碼中存在一個問題這里我們確實將b的值改變了,但是如果我們直接打印b的值會發(fā)現(xiàn)打印出來的值還是變化前的,這是因為編譯器可能直接將b當做一個常量(2)輸出出來了,或者從寄存器中直接獲取的b的值,而沒有重新上內(nèi)存中獲取新的值,導(dǎo)致使用時還是舊值。我們可以通過關(guān)鍵字volatile解決這個問題,被該關(guān)鍵字修飾后每次都會上內(nèi)存中去取值,確保拿到更新后的新值。
8.5、dynamic_cast
dynamic_cast用于將一個父類對象的指針/引用轉(zhuǎn)換為子類對象的指針或引用(動態(tài)轉(zhuǎn)換)
- 向上轉(zhuǎn)型:子類對象指針/引用->父類指針/引用(不需要轉(zhuǎn)換,賦值兼容規(guī)則)
- 向下轉(zhuǎn)型:父類對象指針/引用->子類指針/引用(用dynamic_cast轉(zhuǎn)型是安全的)
注意:
- dynamic_cast只能用于父類含有虛函數(shù)的類。
- dynamic_cast會先檢查是否能轉(zhuǎn)換成功,能成功則轉(zhuǎn)換,不能則返回0(即空指針)。
示例代碼:
class A
{
public:
virtual void f() {}
int _a = 1;
};
class B : public A
{
public:
int _b = 2;
};
void fun(A* pa)
{
// dynamic_cast會先檢查是否能轉(zhuǎn)換成功(指向子類對象),能成功則轉(zhuǎn)換,
// (指向父類對象)不能則返回NULL
// 指向父類轉(zhuǎn)換時有風(fēng)險的,后續(xù)訪問存在越界訪問的風(fēng)險
// 指向子類轉(zhuǎn)換時安全
B* pb1 = dynamic_cast<B*>(pa);
if (pb1)
{
cout << "pb1:" << pb1 << endl;
cout << pb1->_a << endl;
cout << pb1->_b << endl;
pb1->_a++;
pb1->_b++;
cout << pb1->_a << endl;
cout << pb1->_b << endl;
}
else
{
cout << "轉(zhuǎn)換失敗" << endl;
}
}
int main()
{
A a;
B b;
fun(&a);
fun(&b);
return 0;
}解釋:子類轉(zhuǎn)父類沒有問題,主要是父類轉(zhuǎn)子類,當父類指針指向子類對象時可以轉(zhuǎn)換成功,當父類指針指向父類對象時會轉(zhuǎn)換失敗。
注意:強制類型轉(zhuǎn)換關(guān)閉或掛起了正常的類型檢查,每次使用強制類型轉(zhuǎn)換前,程序員應(yīng)該仔細考慮是否還有其他不同的方法達到同一目的,如果非強制類型轉(zhuǎn)換不可,則應(yīng)限制強制轉(zhuǎn)換值的作用域,以減少發(fā)生錯誤的機會。強烈建議:避免使用強制類型轉(zhuǎn)換
九、RTTI
RTTI:Run-time Type identi?cation的簡稱,即:運行時類型識別。
C++通過以下方式來支持RTTI:
- typeid運算符
- dynamic_cast運算符
- decltype
到此這篇關(guān)于C++特殊類設(shè)計及類型轉(zhuǎn)換的文章就介紹到這了,更多相關(guān)C++特殊類設(shè)計及類型轉(zhuǎn)換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言位段(位域)機制結(jié)構(gòu)體的特殊實現(xiàn)及解析
這篇文章主要為大家介紹了C語言位段位域機制結(jié)構(gòu)體的特殊實現(xiàn)講解有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪2022-02-02
select函數(shù)實現(xiàn)高性能IO多路訪問的關(guān)鍵示例深入解析
這篇文章主要為大家介紹了select函數(shù)實現(xiàn)高性能IO多路訪問的關(guān)鍵示例深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09
matlab遺傳算法求解車間調(diào)度問題分析及實現(xiàn)源碼
這篇文章主要為大家介紹了matlab遺傳算法求解車間調(diào)度問題解析,文中附含詳細實現(xiàn)源碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-02-02

