最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++ std::any的模擬實(shí)現(xiàn)

 更新時(shí)間:2024年02月03日 15:00:55   作者:[PE]經(jīng)典八炮  
std::any是C++標(biāo)準(zhǔn)庫(kù)中的一個(gè)類,std::any對(duì)象可以存儲(chǔ)除單例等特殊情況外的任何類型的數(shù)據(jù),本文主要介紹了C++ std::any的模擬實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下

std::any

std::any是C++標(biāo)準(zhǔn)庫(kù)中的一個(gè)類,官網(wǎng)對(duì)它的描述如下:

類 any 描述用于任何可拷貝構(gòu)造類型的單個(gè)值的類型安全容器。

類 any 的對(duì)象存儲(chǔ)任何滿足構(gòu)造函數(shù)要求的類型的一個(gè)實(shí)例或?yàn)榭?,而這被稱為 any 類對(duì)象的狀態(tài)。存儲(chǔ)的實(shí)例被稱作所含對(duì)象。若兩個(gè)狀態(tài)均為空,或均為非空且其所含對(duì)象等價(jià),則兩個(gè)狀態(tài)等價(jià)。

非成員 any_cast 函數(shù)提供對(duì)所含對(duì)象的類型安全訪問(wèn)。

換句話說(shuō),std::any對(duì)象可以存儲(chǔ)任何類型的數(shù)據(jù)(單例等特殊情況除外)。這篇文章來(lái)探討一下如何自己實(shí)現(xiàn)一個(gè)Any類。

Any的基本原理

在C++這種強(qiáng)類型語(yǔ)言中,想用一種類型來(lái)保存多種類型的數(shù)據(jù),首先想到的就是用父類指針(或引用)來(lái)保存子類,實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)。但問(wèn)題是,我們想要保存任意類型,必須使所有類型都有一個(gè)公共的父類。在某些語(yǔ)言(如Java)中,有一個(gè)Object類,是所有類的父類,因此這種語(yǔ)言中就非常容易實(shí)現(xiàn)。但C++的類型系統(tǒng)相當(dāng)混亂,原生類型沒有父類,STL的類型也沒有一個(gè)公共父類,而自定義類型也不會(huì)自動(dòng)繼承自一個(gè)公共父類,因此直接用父類指針不可行。但是如果我們把模板和繼承結(jié)合一下就可以了,為每一種類型創(chuàng)建一個(gè)對(duì)應(yīng)的模板類,這個(gè)模板類又繼承自一個(gè)父類。核心代碼如下:

class AnyHelperBase
{
};
template<typename T>
class AnyHelper :public AnyHelperBase
{
	T data;
};

這樣我們就可以用AnyHelperBase*類型來(lái)存儲(chǔ)任意類型的數(shù)據(jù)了。當(dāng)然,這只是大體思路,還需要具體完善。下面我們將以上述代碼為母體,添加功能。

將數(shù)據(jù)存儲(chǔ)到Any

Any類

在上面的代碼中,如何將數(shù)據(jù)存儲(chǔ)到Any?肯定需要一個(gè)AnyHelperBase*的類型。但考慮到直接操作指針不是很方便,并且std::any使用的時(shí)候并不需要指針,我們應(yīng)該再寫一個(gè)類來(lái)維護(hù)AnyHelperBase*。

class Any
{
private:
	class AnyHelperBase
	{
	public:
	};
	template<typename T>
	class AnyHelper :public AnyHelperBase
	{
	public:
		T data;
	};
	AnyHelperBase* data;
public:
	
};

構(gòu)造函數(shù)

接下來(lái)實(shí)現(xiàn)AnyHelper的構(gòu)造函數(shù)(第一個(gè)是就地構(gòu)造,直接通過(guò)參數(shù)構(gòu)造data,后兩個(gè)是拷貝構(gòu)造):

template<typename ...Args>
AnyHelper(Args&&... args) :data(std::forward<Args>(args)...) {}
AnyHelper(const AnyHelper& other) :data(other.data) {}
AnyHelper(const T& value) :data(value) {}

Any類的構(gòu)造函數(shù):

Any() :data(nullptr) {}
template<typename T>
Any(const T& value) : data(new AnyHelper<std::decay_t<T>>(value)) {}
//Any(const Any& other) :data( ??? ) {}
Any(Any&& other) :data(other.data)
{
	other.data = nullptr;
}

注意:std::decay_t<T>的作用是去掉T的const,引用等亂七八糟的屬性,比如std::decay_t<const int&>的結(jié)果是int。例如,我們顯然不希望傳入const intint得到不同的結(jié)果。這一點(diǎn)很重要,因?yàn)?strong>如果類型不匹配,后面獲取數(shù)據(jù)時(shí)就會(huì)拋出異常!

拷貝構(gòu)造的困難和解決方案

在寫拷貝構(gòu)造(上面代碼的第三個(gè)函數(shù))時(shí),我們遇到了問(wèn)題。由于是深拷貝,我們肯定不能直接復(fù)制指針,而是應(yīng)該再new一個(gè)對(duì)象。但問(wèn)題是,我們?cè)趺传@取另一個(gè)Any中的類型呢?這個(gè)問(wèn)題似乎不好解決,因?yàn)?strong>只有在AnyHelper類內(nèi)部我們才會(huì)知道存儲(chǔ)的類型(這句話很重要)。但我們可以變通一下,讓AnyHelper類直接返回一個(gè)自身的拷貝的指針,我們不必關(guān)心他具體是什么類型。當(dāng)然,我們使用的是AnyHelperBase*,所以AnyHelperBase類里必須就得有這個(gè)函數(shù),換句話說(shuō),這得是一個(gè)虛函數(shù)。在這里我們又用到了多態(tài)的特性。往AnyHelperBase和AnyHelper中添加Clone函數(shù):

class AnyHelperBase
{
public:
	virtual AnyHelperBase* Clone()const = 0;
};
template<typename T>
class AnyHelper :public AnyHelperBase
{
public:
	T data;
	template<typename ...Args>
	AnyHelper(Args&&... args) :data(std::forward<Args>(args)...) {}
	AnyHelper(const AnyHelper& other) :data(other.data) {}
	AnyHelper(const T& value) :data(value) {}
	virtual AnyHelper* Clone()const
	{
		return new AnyHelper(*this);
	}
};

Any類的拷貝構(gòu)造函數(shù):

Any(const Any& other) :data(other.data->Clone()) {}

賦值運(yùn)算符

賦值運(yùn)算符和構(gòu)造函數(shù)基本一樣,需要注意的是delete原來(lái)的data

template<typename T>
Any& operator=(const T& value)
{
	if (data != nullptr)
		delete data;
	data = new AnyHelper<std::decay_t<T>>(value);
	return *this;
}
Any& operator=(const Any& other)
{
	if (data != nullptr)
		delete data;
	data = other.data->Clone();
	return *this;
}
Any& operator=(Any&& other)
{
	if (data != nullptr)
		delete data;
	data = other.data;
	other.data = nullptr;
	return *this;
}

其他賦值類函數(shù)

注意到std::any可以有空值,并且可以設(shè)置為空,我們也寫一個(gè)Reset函數(shù)將Any設(shè)為空。

void Reset()
{
	if (data != nullptr)
		delete data;
	data = nullptr;
}

另外,為了優(yōu)化性能,并且支持一些不可移動(dòng)和拷貝的類型,我們添加就地構(gòu)造函數(shù),可以直接通過(guò)參數(shù)構(gòu)造一個(gè)對(duì)象。

template<typename T, typename ...Args>
std::decay_t<T>& Emplace(Args&&... args)
{
	if (data != nullptr)
		delete data;
	auto temp = new AnyHelper<std::decay_t<T>>(std::forward<Args>(args)...);
	data = temp;
	return temp->data;
}

還有一個(gè)簡(jiǎn)單的Swap,直接交換data指針:

void Swap(Any& other)
{
	AnyHelperBase* temp = this->data;
	this->data = other.data;
	other.data = temp;
}

到這里,Any類就可以存儲(chǔ)數(shù)據(jù)了。

從Any獲取數(shù)據(jù):Any轉(zhuǎn)換為其他類型

對(duì)一個(gè)實(shí)用的Any類來(lái)說(shuō),獲取數(shù)據(jù)也是必不可少的,實(shí)現(xiàn)獲取數(shù)據(jù)即將Any轉(zhuǎn)換為其他類型。對(duì)std::any來(lái)說(shuō),有std::any_cast函數(shù)來(lái)實(shí)現(xiàn)這一轉(zhuǎn)換,我們也寫一個(gè)AnyCast函數(shù)。

template<typename T>
T AnyCast(const Any& any)
{
	auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any.data);
	if (p == nullptr)
		throw std::runtime_error("Bad any cast!");
	return p->data;
}
template<typename T>
T AnyCast(Any& any)
{
	auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any.data);
	if (p == nullptr)
		throw std::runtime_error("Bad any cast!");
	return p->data;
}
template<typename T>
T AnyCast(Any&& any)
{
	auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any.data);
	if (p == nullptr)
		throw std::runtime_error("Bad any cast!");
	return p->data;
}
template<typename T>
const T* AnyCast(const Any* any)
{
	auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any->data);
	if (p == nullptr)
		return nullptr;
	return &p->data;
}
template<typename T>
T* AnyCast(Any* any)
{
	auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any->data);
	if (p == nullptr)
		return nullptr;
	return &p->data;
}

AnyCast一共有5個(gè)重載(和STL中的一致),前三個(gè)是一組,后兩個(gè)是一組。前三個(gè)的特性是轉(zhuǎn)換失敗會(huì)拋出異常,后兩個(gè)接受指針,返回指針,失敗不會(huì)拋異常,而是會(huì)返回空指針。5個(gè)函數(shù)實(shí)現(xiàn)原理都是一樣的,核心就是使用dynamic_cast將AnyHelperBase*類型的data轉(zhuǎn)換為相應(yīng)的AnyHelper子類。dynamic_cast是向下轉(zhuǎn)換的操作符,也支持運(yùn)行時(shí)多態(tài),如果轉(zhuǎn)換失敗會(huì)返回空指針。

獲取Any信息

到現(xiàn)在,一個(gè)Any類的核心功能已經(jīng)全部完成,不過(guò)為了模擬std::any,我們還是再添加一些獲取信息的函數(shù)。

獲取類型的type_info

我們前面說(shuō)過(guò),在我們實(shí)現(xiàn)的Any類中,只有在AnyHelper類內(nèi)部我們才會(huì)知道存儲(chǔ)的類型。因此,獲取類型必須從AnyHelper類下首。類似于Clone,我們?cè)贋锳nyHelperBase和AnyHelper添加一個(gè)虛函數(shù):

class AnyHelperBase
{
public:
	virtual const std::type_info& Type()const = 0;
	virtual AnyHelperBase* Clone()const = 0;
};
template<typename T>
class AnyHelper :public AnyHelperBase
{
public:
	T data;
	//構(gòu)造函數(shù)省略
	//...
	virtual const std::type_info& Type()const
	{
		return typeid(T);
	}
	virtual AnyHelper* Clone()const
	{
		return new AnyHelper(*this);
	}
};

這樣Any類的Type就好寫了:

const std::type_info& Type()const
{
	return data->Type();
}

HasValue

沒啥好說(shuō)的…

bool HasValue()const
{
	return data != nullptr;
}

析構(gòu)函數(shù)

在這里我提醒一下大家,雖然析構(gòu)函數(shù)很簡(jiǎn)單,但一定不要忘了寫,否則會(huì)引起內(nèi)存泄漏!檢查析構(gòu)函數(shù)是一個(gè)很好的代碼習(xí)慣!

~Any()
{
	if (data != nullptr)
		delete data;
}

附錄:完整代碼

到這里,整個(gè)Any類就完成了。下面是完整代碼:

namespace MyStd
{
	class Any
	{
	private:
		class AnyHelperBase
		{
		public:
			virtual const std::type_info& Type()const = 0;
			virtual AnyHelperBase* Clone()const = 0;
		};
		template<typename T>
		class AnyHelper :public AnyHelperBase
		{
		public:
			T data;
			template<typename ...Args>
			AnyHelper(Args&&... args) :data(std::forward<Args>(args)...) {}
			AnyHelper(const AnyHelper& other) :data(other.data) {}
			AnyHelper(const T& value) :data(value) {}
			virtual const std::type_info& Type()const
			{
				return typeid(T);
			}
			virtual AnyHelper* Clone()const
			{
				return new AnyHelper(*this);
			}
		};
		template<typename T>
		friend T AnyCast(const Any& any);
		template<typename T>
		friend T AnyCast(Any& any);
		template<typename T>
		friend T AnyCast(Any&& any);
		template<typename T>
		friend const T* AnyCast(const Any* any);
		template<typename T>
		friend T* AnyCast(Any* any);
		AnyHelperBase* data;
	public:
		Any() :data(nullptr) {}
		template<typename T>
		Any(const T& value) : data(new AnyHelper<std::decay_t<T>>(value)) {}
		Any(const Any& other) :data(other.data->Clone()) {}
		Any(Any&& other) :data(other.data)
		{
			other.data = nullptr;
		}
		const std::type_info& Type()const
		{
			return data->Type();
		}
		bool HasValue()const
		{
			return data != nullptr;
		}
		void Reset()
		{
			if (data != nullptr)
				delete data;
			data = nullptr;
		}
		template<typename T>
		Any& operator=(const T& value)
		{
			if (data != nullptr)
				delete data;
			data = new AnyHelper<std::decay_t<T>>(value);
			return *this;
		}
		Any& operator=(const Any& other)
		{
			if (data != nullptr)
				delete data;
			data = other.data->Clone();
			return *this;
		}
		Any& operator=(Any&& other)
		{
			if (data != nullptr)
				delete data;
			data = other.data;
			other.data = nullptr;
			return *this;
		}
		void Swap(Any& other)
		{
			AnyHelperBase* temp = this->data;
			this->data = other.data;
			other.data = temp;
		}
		template<typename T, typename ...Args>
		std::decay_t<T>& Emplace(Args&&... args)
		{
			if (data != nullptr)
				delete data;
			auto temp = new AnyHelper<std::decay_t<T>>(std::forward<Args>(args)...);
			data = temp;
			return temp->data;
		}
		~Any()
		{
			if (data != nullptr)
				delete data;
		}
	};

	template<typename T>
	T AnyCast(const Any& any)
	{
		auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any.data);
		if (p == nullptr)
			throw std::runtime_error("Bad any cast!");
		return p->data;
	}
	template<typename T>
	T AnyCast(Any& any)
	{
		auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any.data);
		if (p == nullptr)
			throw std::runtime_error("Bad any cast!");
		return p->data;
	}
	template<typename T>
	T AnyCast(Any&& any)
	{
		auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any.data);
		if (p == nullptr)
			throw std::runtime_error("Bad any cast!");
		return p->data;
	}
	template<typename T>
	const T* AnyCast(const Any* any)
	{
		auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any->data);
		if (p == nullptr)
			return nullptr;
		return &p->data;
	}
	template<typename T>
	T* AnyCast(Any* any)
	{
		auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any->data);
		if (p == nullptr)
			return nullptr;
		return &p->data;
	}
}

到此這篇關(guān)于C++ std::any的模擬實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C++ std::any內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • C語(yǔ)言超全面講解函數(shù)的使用方法下

    C語(yǔ)言超全面講解函數(shù)的使用方法下

    函數(shù)是一組一起執(zhí)行一個(gè)任務(wù)的語(yǔ)句。每個(gè)?C?程序都至少有一個(gè)函數(shù),即主函數(shù)?main()?,所有簡(jiǎn)單的程序都可以定義其他額外的函數(shù),由于篇幅過(guò)大,分為兩篇講解,下面開始下篇
    2022-04-04
  • C語(yǔ)言實(shí)現(xiàn)可排序通訊錄的示例代碼

    C語(yǔ)言實(shí)現(xiàn)可排序通訊錄的示例代碼

    本文主要介紹了C語(yǔ)言實(shí)現(xiàn)可排序通訊錄的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • VC++實(shí)現(xiàn)程序開機(jī)啟動(dòng)運(yùn)行的方法

    VC++實(shí)現(xiàn)程序開機(jī)啟動(dòng)運(yùn)行的方法

    這篇文章主要介紹了VC++實(shí)現(xiàn)程序開機(jī)啟動(dòng)運(yùn)行的方法,很實(shí)用的功能,需要的朋友可以參考下
    2014-08-08
  • C++函數(shù)指針+對(duì)象指針+this指針+指向類靜態(tài)和非靜態(tài)成員的指針

    C++函數(shù)指針+對(duì)象指針+this指針+指向類靜態(tài)和非靜態(tài)成員的指針

    這篇文章主要介紹了C++函數(shù)指針+對(duì)象指針+this指針+指向類靜態(tài)和非靜態(tài)成員的指針,函數(shù)指針定義和賦值的語(yǔ)法指其中數(shù)據(jù)類型代表指向函數(shù)的返回類型,形參表為指向函數(shù)的形參表,更多相關(guān)資料需要的朋友可以參考一下下面文章內(nèi)容
    2022-03-03
  • C++連連看判定圖形消除算法

    C++連連看判定圖形消除算法

    這篇文章主要為大家詳細(xì)介紹了C++連連看判定圖形消除算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • 數(shù)據(jù)結(jié)構(gòu)之帶頭結(jié)點(diǎn)的單鏈表

    數(shù)據(jù)結(jié)構(gòu)之帶頭結(jié)點(diǎn)的單鏈表

    單鏈表是一種鏈?zhǔn)酱嫒〉臄?shù)據(jù)結(jié)構(gòu),用一組地址任意的存儲(chǔ)單元存放線性表中的數(shù)據(jù)元素。鏈表中的數(shù)據(jù)是以結(jié)點(diǎn)來(lái)表示的,每個(gè)結(jié)點(diǎn)的構(gòu)成:數(shù)據(jù)域(數(shù)據(jù)元素的映象)?+?指針域(指示后繼元素存儲(chǔ)位置),元素就是存儲(chǔ)數(shù)據(jù)的存儲(chǔ)單元,指針就是連接每個(gè)結(jié)點(diǎn)的地址數(shù)據(jù)
    2023-07-07
  • C語(yǔ)言實(shí)現(xiàn)堆的簡(jiǎn)單操作的示例代碼

    C語(yǔ)言實(shí)現(xiàn)堆的簡(jiǎn)單操作的示例代碼

    堆(heap)是計(jì)算機(jī)科學(xué)中一類特殊的數(shù)據(jù)結(jié)構(gòu)的統(tǒng)稱。堆通常是一個(gè)可以被看做一棵樹的數(shù)組對(duì)象。本文介紹了C語(yǔ)言中堆的一些簡(jiǎn)單操作,需要的可以參考一下
    2022-11-11
  • VC編程控件類HTControl之CHTGDIManager GDI資源管理類用法解析

    VC編程控件類HTControl之CHTGDIManager GDI資源管理類用法解析

    這篇文章主要介紹了VC編程控件類HTControl之CHTGDIManager GDI資源管理類用法解析,需要的朋友可以參考下
    2014-08-08
  • C++游戲教程基本技巧之隨機(jī)化詳解

    C++游戲教程基本技巧之隨機(jī)化詳解

    在小游戲的制作中時(shí)常常會(huì)要用到隨機(jī)數(shù),這篇文章就來(lái)和大家談?wù)凜++中這個(gè)所謂的“隨機(jī)”。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2022-11-11
  • C++?spdlog?日志庫(kù)使用小結(jié)

    C++?spdlog?日志庫(kù)使用小結(jié)

    spdlog是目前?C++?生態(tài)中性能最高(每秒可處理數(shù)百萬(wàn)條消息)、使用最廣泛的現(xiàn)代日志庫(kù)之一,下面就來(lái)詳細(xì)的介紹下spdlog?日志庫(kù)使用,感興趣的可以了解一下
    2026-06-06

最新評(píng)論

东源县| 巴南区| 辽阳县| 兰溪市| 神池县| 吉安市| 南投县| 西藏| 海晏县| 潼关县| 太湖县| 巴彦淖尔市| 桓仁| 富民县| 白玉县| 星座| 潍坊市| 泰和县| 特克斯县| 肃南| 揭阳市| 峡江县| 织金县| 石柱| 平遥县| 崇仁县| 邵东县| 丽水市| 大化| 罗源县| 巴里| 元朗区| 大邑县| 赣榆县| 隆化县| 瑞金市| 金沙县| 屯门区| 石阡县| 托克托县| 霍城县|