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

C++可調(diào)用對(duì)象callable object深入分析

 更新時(shí)間:2022年08月25日 09:09:34   作者:殺神李  
所謂的callable object,表示可以被某種方式調(diào)用其某些函數(shù)的對(duì)象。它可以是:一個(gè)函數(shù)、一個(gè)指向成員函數(shù)的指針、一個(gè)函數(shù)對(duì)象,該對(duì)象擁有operator()、一個(gè)lambda表達(dá)式,嚴(yán)格的說(shuō)它是一種函數(shù)對(duì)象

本作者一致的觀點(diǎn)就是 在任何語(yǔ)言執(zhí)行的時(shí)候先去思考匯編層面能不能做到 如果能做到 那么高級(jí)語(yǔ)言才能做到 無(wú)論你推出什么新特性 用戶態(tài)匯編你都是繞不開的 比如你要調(diào)用函數(shù) 那么你必須要使用call指令 那么就必須要有函數(shù)地址 接下來(lái)我們來(lái)詳細(xì)說(shuō)說(shuō)為什么c++11要推出這個(gè)新概念 以及他解決了什么問(wèn)題 還有如何使用它

Tips:c++的設(shè)計(jì)哲學(xué)是你必須時(shí)刻清楚你自己在干什么 stl內(nèi)部并不會(huì)給你執(zhí)行任何的安全檢查 程序直接崩潰也是完全有可能的 功力不夠 就不要玩花的

為什么需要他

在c++11還沒(méi)有推出callable object的時(shí)候 那時(shí)候如果你想要把普通函數(shù)當(dāng)做參數(shù)一樣傳遞那么你就只能使用函數(shù)指針 如下段代碼所示

我就不再演示如果你有函數(shù)指針如何調(diào)用函數(shù)了 空指針發(fā)生調(diào)用異常啥的也是你自己的問(wèn)題那非常簡(jiǎn)單了 不需要過(guò)多描述

注意 FuncP是一種類型 而非一個(gè)指針

#include <iostream>
void test(int i)
{
	return;
}
typedef void(*FuncP)(int i);
void recevier(void(*)(int))
{
	std::cout << "recevier working!" << std::endl;
}
int main()
{
	recevier(&test);
	FuncP ding = test;
	recevier(&test);
	void(*FuncP1)(int) = test;
	recevier(FuncP1);
}

運(yùn)行結(jié)果截圖:

而如果你想把類的成員函數(shù)傳遞 那更是麻煩 因?yàn)槲覀冎李惖某蓡T函數(shù)在調(diào)用的時(shí)候是需要傳遞this指針的 那么我們來(lái)看一看如何傳遞類的成員函數(shù) 如下段代碼所示

#include <iostream>
class testclass
{
public:
	void MemberFunc(int i)
	{
		std::cout << "MemberFunc" << std::endl;
	}
};
typedef void(testclass::* CFuncP)(int);
void recevier(void(testclass::* memberFunc)(int))
{
	testclass p;
	(p.*memberFunc)(1);
	std::cout << "recevier working!" << std::endl;
}
void recevier(void(*)(int))
{
	std::cout << "recevier working!" << std::endl;
}
int main()
{
	recevier(&testclass::MemberFunc);
	CFuncP ding = &testclass::MemberFunc;
	recevier(ding);
	void(testclass:: * testF)(int) = &testclass::MemberFunc;
	recevier(testF);
}

運(yùn)行結(jié)果如下圖

可以看到啊 雖然咱們用普通的成員函數(shù)指針和普通的函數(shù)指針?biāo)坪跻呀?jīng)可以解決絕大部分問(wèn)題 那為什么又要推出一個(gè)callable object呢? 關(guān)鍵在于這種代碼實(shí)現(xiàn)起來(lái) 其實(shí)可讀性很差 而且不是那么好理解 如果有一種統(tǒng)一的方式來(lái)讓我們可以把函數(shù)當(dāng)做參數(shù)傳遞 并且能直接調(diào)用就好了 那么c++11便推出了callable object

他究竟是啥

那么究竟什么叫做callable object呢 顧名思義 就是可以被調(diào)用的對(duì)象 看如下一個(gè)最簡(jiǎn)單的例子

#include <iostream>
class testclass
{
public:
	void MemberFunc(int i)
	{
		std::cout << "MemberFunc" << std::endl;
	}
	void operator()()
	{
		std::cout << "callable object working" << std::endl;
	}
};
int main()
{
	testclass ding;
	ding();
}

當(dāng)一個(gè)對(duì)象 重載了() 運(yùn)算符的時(shí)候 我們就把他看做 一個(gè)最簡(jiǎn)單的callable object 因?yàn)樗@個(gè)對(duì)象可以像函數(shù)一樣被調(diào)用是吧 沒(méi)有什么問(wèn)題 那么接下來(lái)我們就來(lái)看看stl提供的 能讓你快速生成callable object的組件之std::bind

他怎樣被使用呢

我們先來(lái)看一個(gè)最簡(jiǎn)單的例子 基于std::bind

void test(int i, int j, int k)
{
	std::cout << "test working!" << std::endl;
	std::cout << i << std::endl;
	std::cout << j << std::endl;
	std::cout << k << std::endl;
}
int main()
{
	std::bind(&test, 1, 2, 3)();
}

如上圖所示 我們使用std::bind來(lái)創(chuàng)建了一個(gè)callable object并且在創(chuàng)建這個(gè)callable object的時(shí)候就已經(jīng)把他三個(gè)參數(shù)傳遞好了 這點(diǎn)非常重要 這會(huì)影響到接下來(lái)的占位符的講解 然后馬上使用()來(lái)調(diào)用了他 運(yùn)行結(jié)果如下圖所示

相比較于普通的函數(shù)指針 這樣的方式是不是更簡(jiǎn)單明了了呢? 當(dāng)然這遠(yuǎn)遠(yuǎn)不是他的全部 接下來(lái)我們來(lái)看看使用占位符的時(shí)候 該如何使用它 代碼如下圖所示

void test(int i, int j, int k)
{
	std::cout << "test working!" << std::endl;
	std::cout << i << std::endl;
	std::cout << j << std::endl;
	std::cout << k << std::endl;
}
int main()
{
	std::bind(&test, 1,std::placeholders::_1,std::placeholders::_2)(2,3);
}

可以看到上圖 我們?cè)趧?chuàng)建callable object的時(shí)候 并沒(méi)有去傳遞全部的參數(shù) 而是使用了占位符 然后在真正調(diào)用的時(shí)候才去傳遞了2和3兩個(gè)參數(shù) 運(yùn)行結(jié)果如下圖所示

下面讓我們升華到成員函數(shù)好嘛? 不過(guò)多講解 咱們直接看代碼

#include <iostream>
#include <functional>
class testclass
{
public:
	void MemberFunc(int i,int j,int k)
	{
		std::cout << "MemberFunc" << std::endl;
		std::cout << i << std::endl;
		std::cout << j << std::endl;
		std::cout << k << std::endl;
	}
	void operator()()
	{
		std::cout << "callable object working" << std::endl;
	}
};
int main()
{
	std::bind(&testclass::MemberFunc, testclass(), 1, std::placeholders::_1, std::placeholders::_2)(2, 3);
}

成員函數(shù)的調(diào)用時(shí)需要this指針的 我相信大家都知道 那么這就是為什么我在std::bind的第二個(gè)參數(shù)創(chuàng)建了一個(gè)臨時(shí)對(duì)象 用來(lái)傳遞this指針 可以看到相比較于普通的成員函數(shù)指針 這種方式明顯要方便的多 注意啊 使用std::bind來(lái)創(chuàng)建成員函數(shù)的callable object的時(shí)候 第二個(gè)參數(shù)必須是對(duì)象或者某個(gè)對(duì)象的this指針 不然直接會(huì)G的

亂玩導(dǎo)致的G 你自己負(fù)責(zé) 如下圖所示

當(dāng)然 像下圖這樣先使用占位符將傳入對(duì)象暫定 然后在參數(shù)中去傳遞對(duì)象或this指針也是可以的

std::bind
(&testclass::MemberFunc,std::placeholders::_1, 1, std::placeholders::_2,
std::placeholders::_3)(testclass(),2, 3);

這個(gè)時(shí)候你就要問(wèn)了 OK 這樣確實(shí)很方便 沒(méi)錯(cuò) 但是你說(shuō)了這么久也沒(méi)見(jiàn)你把它當(dāng)做參數(shù)來(lái)傳遞啊 下面就來(lái)介紹std::function 他不僅能當(dāng)做參數(shù)來(lái)傳遞 并且還可以保存callable object 屬實(shí)是非常方便 老樣子 還是從最簡(jiǎn)單的例子開始 代碼如下圖

#include <iostream>
#include <functional>
class testclass
{
public:
	int ding{};
	void MemberFunc(int i,int j,int k)
	{
		std::cout << "MemberFunc" << std::endl;
		std::cout << i << std::endl;
		std::cout << j << std::endl;
		std::cout << k << std::endl;
		std::cout << ding << std::endl;
	}
	void operator()()
	{
		std::cout << "callable object working" << std::endl;
	}
};
int main()
{
	std::function<void(int,int,int)>MemberCall=std::bind(&testclass::MemberFunc,testclass(), 1, std::placeholders::_1, std::placeholders::_2);
	MemberCall(1,2,NULL);
	std::function<void(testclass&, int, int, int) > MemberCall2=&testclass::MemberFunc;
	testclass C;
	MemberCall2(C, 1, 1, 1);
}

如上圖所示 因?yàn)槲乙呀?jīng)放置了一個(gè)占位符 所以呢 第三個(gè)參數(shù)無(wú)論你填什么 都是沒(méi)用的 只會(huì)取前兩個(gè)參數(shù) 調(diào)用結(jié)果如下所示:

我們?cè)賮?lái)試試將他作為參數(shù)傳遞 很簡(jiǎn)單咯 玩起來(lái)

void test(std::function<void(int, int, int)>& Func, int c)
{
	Func(1, 2, 3);
	std::cout << c<<std::endl;
}
int main()
{
	std::function<void(int,int,int)>MemberCall=std::bind(&testclass::MemberFunc,testclass(), 1, std::placeholders::_1, std::placeholders::_2);
	MemberCall(1,2,NULL);
	std::function<void(testclass&, int, int, int) > MemberCall2=&testclass::MemberFunc;
	testclass C;
	MemberCall2(C, 1, 1, 1);
	test(MemberCall, 3);
}

運(yùn)行結(jié)果如下:

看看 有了std::function和std::bind 函數(shù)就像對(duì)象一樣可以被傳遞保存和調(diào)用 是不是很方便呢

Tips:既然他是一個(gè)對(duì)象了 那任何對(duì)對(duì)象的操作對(duì)于他都是允許的 比如塞入隊(duì)列啥的 可以任意交互 其他東西我就不演示了 對(duì)于對(duì)象的各種操作是基本知識(shí)

最后讓我們來(lái)看看他跟lambda之間的化學(xué)反應(yīng) 代碼如下:

#include <iostream>
#include <functional>
class testclass
{
public:
	int ding{};
	void MemberFunc(int i,int j,int k)
	{
		std::cout << "MemberFunc" << std::endl;
		std::cout << i << std::endl;
		std::cout << j << std::endl;
		std::cout << k << std::endl;
		std::cout << ding << std::endl;
	}
	void operator()()
	{
		std::cout << "callable object working" << std::endl;
	}
};
void test(std::function<void(int, int, int)>& Func, int c)
{
	Func(1, 2, 3);
	std::cout << c<<std::endl;
}
int main()
{
	std::function<void(int,int,int)>MemberCall=std::bind(&testclass::MemberFunc,testclass(), 1, std::placeholders::_1, std::placeholders::_2);
	std::function<void(testclass&&,int, int, int)>MemberCall1 = std::bind(&testclass::MemberFunc, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,std::placeholders::_4);
	MemberCall1(testclass(),1, 2, 3);
	MemberCall(1,2,3);
	std::function<void(testclass&, int, int, int) > MemberCall2=&testclass::MemberFunc;
	testclass C;
	MemberCall2(C, 1, 1, 1);
	test(MemberCall, 3);
	std::function<bool(int,int,int)> play=std::bind([&C](testclass& c, int i, int j, int k)->bool {
		c.MemberFunc(i, j, k);
		std::cout << "lambda working!" << std::endl;
		}, C, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
	play(1, 2, 3);
}

運(yùn)行結(jié)果如下

相信細(xì)心的小伙伴已經(jīng)發(fā)現(xiàn)我多加了一個(gè)Membercall1 并且使用了右值引用 關(guān)于這個(gè) 我們下一篇文章再說(shuō)好嘛? 本期callable object講解結(jié)束 認(rèn)真看完相信你能學(xué)到很多東西

到此這篇關(guān)于C++可調(diào)用對(duì)象callable object深入分析的文章就介紹到這了,更多相關(guān)C++ callable object內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:

相關(guān)文章

  • OpenMP?Parallel?Construct的實(shí)現(xiàn)原理詳解

    OpenMP?Parallel?Construct的實(shí)現(xiàn)原理詳解

    在本篇文章當(dāng)中我們將主要分析?OpenMP?當(dāng)中的?parallel?construct?具體時(shí)如何實(shí)現(xiàn)的,以及這個(gè)?construct?調(diào)用了哪些運(yùn)行時(shí)庫(kù)函數(shù),并且詳細(xì)分析這期間的參數(shù)傳遞,需要的可以參考一下
    2023-01-01
  • C/C++指針與內(nèi)存管理圖文詳解

    C/C++指針與內(nèi)存管理圖文詳解

    這篇文章主要為大家詳細(xì)介紹了C/C++指針與內(nèi)存管理,使用文圖并敘的方式,文中圖片介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 詳解c++ libuv工作隊(duì)列

    詳解c++ libuv工作隊(duì)列

    這篇文章主要介紹了c++ libuv工作隊(duì)列的相關(guān)資料,幫助大家更好的理解和使用libuv,感興趣的朋友可以了解下
    2021-02-02
  • QT與MATLAB混合編程的詳細(xì)教程

    QT與MATLAB混合編程的詳細(xì)教程

    最近項(xiàng)目需要,matlab的一些算法需要工程用,因此需要直接轉(zhuǎn)成Qt能夠調(diào)用的形式,下面這篇文章主要給大家介紹了關(guān)于QT與MATLAB混合編程的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • 關(guān)于STL中set容器的一些總結(jié)

    關(guān)于STL中set容器的一些總結(jié)

    關(guān)于set,必須說(shuō)明的是set關(guān)聯(lián)式容器。set作為一個(gè)容器也是用來(lái)存儲(chǔ)同一數(shù)據(jù)類型的數(shù)據(jù)類型,并且能從一個(gè)數(shù)據(jù)集合中取出數(shù)據(jù),在set中每個(gè)元素的值都唯一,而且系統(tǒng)能根據(jù)元素的值自動(dòng)進(jìn)行排序
    2013-09-09
  • C++ auto類型說(shuō)明符

    C++ auto類型說(shuō)明符

    在C++11中引入了auto類型說(shuō)明符,用它就能讓編譯器替我們?nèi)シ治霰磉_(dá)式所屬的類型。當(dāng)然,auto變量必須有初始值,這樣編譯器才能推斷其類型
    2016-03-03
  • C++依賴倒轉(zhuǎn)原則和里氏代換原則有什么好處

    C++依賴倒轉(zhuǎn)原則和里氏代換原則有什么好處

    設(shè)計(jì)模式(Design pattern)代表了最佳的實(shí)踐,通常被有經(jīng)驗(yàn)的面向?qū)ο蟮能浖_發(fā)人員所采用。設(shè)計(jì)模式是軟件開發(fā)人員在軟件開發(fā)過(guò)程中面臨的一般問(wèn)題的解決方案。本篇介紹設(shè)計(jì)模式七大原則之一的依賴倒轉(zhuǎn)原則
    2023-02-02
  • VC++實(shí)現(xiàn)CStdioFile寫入及讀取文件并自動(dòng)換行的方法

    VC++實(shí)現(xiàn)CStdioFile寫入及讀取文件并自動(dòng)換行的方法

    這篇文章主要介紹了VC++實(shí)現(xiàn)CStdioFile寫入及讀取文件并自動(dòng)換行的方法,很實(shí)用的功能,需要的朋友可以參考下
    2014-08-08
  • 淺談QT內(nèi)存泄漏

    淺談QT內(nèi)存泄漏

    本文主要介紹了淺談QT內(nèi)存泄漏,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • visual studio code 編譯運(yùn)行html css js文件的教程

    visual studio code 編譯運(yùn)行html css js文件的教程

    這篇文章主要介紹了visual studio code 如何編譯運(yùn)行html css js文件,本文通過(guò)圖文實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03

最新評(píng)論