欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++特殊類設(shè)計及類型轉(zhuǎn)換舉例詳解

 更新時間:2025年05月02日 09:49:16   作者:孞?¥  
這篇文章主要介紹了C++中如何設(shè)計不能被拷貝、只能在堆上或棧上創(chuàng)建對象的類、不能被繼承的類以及單例模式的實現(xiàn)方法,還討論了C++中的類型轉(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++實現(xiàn)分數(shù)計算器

    C++實現(xiàn)分數(shù)計算器

    這篇文章主要為大家詳細介紹了C++實現(xiàn)分數(shù)計算器,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • C語言位段(位域)機制結(jié)構(gòu)體的特殊實現(xiàn)及解析

    C語言位段(位域)機制結(jié)構(gòu)體的特殊實現(xiàn)及解析

    這篇文章主要為大家介紹了C語言位段位域機制結(jié)構(gòu)體的特殊實現(xiàn)講解有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2022-02-02
  • C++流操作之fstream用法介紹

    C++流操作之fstream用法介紹

    這篇文章詳細介紹了C++流操作之fstream的用法,有需要的朋友可以參考一下
    2013-09-09
  • 深入淺析c/c++ 中的static關(guān)鍵字

    深入淺析c/c++ 中的static關(guān)鍵字

    C++的static有兩種用法:面向過程程序設(shè)計中的static和面向?qū)ο蟪绦蛟O(shè)計中的static。本文重點給大家介紹c/c++ 中的static關(guān)鍵字,感興趣的朋友跟隨小編一起看看吧
    2018-08-08
  • 詳解用C語言實現(xiàn)三子棋游戲流程

    詳解用C語言實現(xiàn)三子棋游戲流程

    三子棋是一種民間傳統(tǒng)游戲,又叫九宮棋、圈圈叉叉、一條龍、井字棋等。將正方形對角線連起來,相對兩邊依次擺上三個雙方棋子,只要將自己的三個棋子走成一條線,對方就算輸了
    2021-11-11
  • select函數(shù)實現(xiàn)高性能IO多路訪問的關(guān)鍵示例深入解析

    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)源碼

    這篇文章主要為大家介紹了matlab遺傳算法求解車間調(diào)度問題解析,文中附含詳細實現(xiàn)源碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2022-02-02
  • C++設(shè)計與聲明超詳細講解

    C++設(shè)計與聲明超詳細講解

    C++軟件開發(fā)可以理解為設(shè)計一系列的類,讓這些類相互使用,最終實現(xiàn)我們所需要的功能。類與類之間的相互關(guān)系可以很復(fù)雜,也可以很簡單,如何簡單高效的描述類與類之間的關(guān)系是設(shè)計的難點之一。遵循本文所提供的方法,將會給你一些靈感
    2022-09-09
  • 用C語言實現(xiàn)井字棋游戲代碼

    用C語言實現(xiàn)井字棋游戲代碼

    大家好,本篇文章主要講的是用C語言實現(xiàn)井字棋游戲代碼,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01
  • 算法詳解之回溯法具體實現(xiàn)

    算法詳解之回溯法具體實現(xiàn)

    這篇文章主要介紹了算法詳解之回溯法具體實現(xiàn),需要的朋友可以參考下
    2014-02-02

最新評論