亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C++中各種可調(diào)用對(duì)象深入講解

 更新時(shí)間:2019年02月15日 08:30:44   作者:悠悠  
這篇文章主要給大家介紹了關(guān)于C++中各種可調(diào)用對(duì)象的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

概述

一組執(zhí)行任務(wù)的語(yǔ)句都可以視為一個(gè)函數(shù),一個(gè)可調(diào)用對(duì)象。在程序設(shè)計(jì)的過(guò)程中,我們習(xí)慣于把那些具有復(fù)用性的一組語(yǔ)句抽象為函數(shù),把變化的部分抽象為函數(shù)的參數(shù)。

函數(shù)的使用能夠極大的極少代碼重復(fù)率,提高代碼的靈活性。

C++中具有函數(shù)這種行為的方式有很多。就函數(shù)調(diào)用方式而言

func(param1, param2);

這兒使用func作為函數(shù)調(diào)用名,param1和param2為函數(shù)參數(shù)。在C++中就func的類(lèi)型,可能為:

  • 普通函數(shù)
  • 類(lèi)成員函數(shù)
  • 類(lèi)靜態(tài)函數(shù)
  • 仿函數(shù)
  • 函數(shù)指針
  • lambda表達(dá)式 C++11加入標(biāo)準(zhǔn)
  • std::function C++11加入標(biāo)準(zhǔn)

下面就這幾種函數(shù)展開(kāi)介紹

簡(jiǎn)單函數(shù)形式

普通函數(shù)

這種函數(shù)定義比較簡(jiǎn)單,一般聲明在一個(gè)文件開(kāi)頭。如下:

#include <iostream>

// 普通函數(shù)聲明和定義
int func_add(int a, int b) { return a + b; }

int main()
{
  int a = 10;
  int b = 20;
  int sum = func_add(a, b);
  std::cout << a << "+" << b << "is : " << sum << std::endl;
  getchar();
  return 0;
}

類(lèi)成員函數(shù)

在一個(gè)類(lèi)class中定義的函數(shù)一般稱(chēng)為類(lèi)的方法,分為成員方法和靜態(tài)方法,區(qū)別是成員方法的參數(shù)列表中隱含著類(lèi)this指針。

#include <iostream>

class Calcu
{
public:
  int base = 20;
  // 類(lèi)的成員方法,參數(shù)包含this指針
  int class_func_add(const int a, const int b) const { return this->base + a + b; };
  // 類(lèi)的靜態(tài)成員方法,不包含this指針
  static int class_static_func_add(const int a, const int b) { return a + b; };
};

int main(void) 
{
  Calcu obj;
  int a = 10;
  int b = 20;

  // 類(lèi)普通成員方法調(diào)用如下
  obj.class_func_add(a, b);

  // 類(lèi)靜態(tài)成員方法調(diào)用如下
  obj.class_static_func_add(a, b);
  Calcu::class_static_func_add(a, b);

  getchar();
  return 0;
}

仿函數(shù)

仿函數(shù)是使用類(lèi)來(lái)模擬函數(shù)調(diào)用行為,我們只要重載一個(gè)類(lèi)的operator()方法,即可像調(diào)用一個(gè)函數(shù)一樣調(diào)用類(lèi)。這種方式用得比較少。

class ImitateAdd
{
public:
  int operator()(const int a, const int b) const { return a + b; };
};

int main()
{
  // 首先創(chuàng)建一個(gè)仿函數(shù)對(duì)象,然后調(diào)用()運(yùn)算符模擬函數(shù)調(diào)用
  ImitateAdd imitate;
  imitate(5, 10);

  getchar();
  return 0;
}

函數(shù)指針

顧名思義,函數(shù)指針可以理解為指向函數(shù)的指針??梢詫⒑瘮?shù)名賦值給相同類(lèi)型的函數(shù)指針,通過(guò)調(diào)用函數(shù)指針實(shí)現(xiàn)調(diào)用函數(shù)。

函數(shù)指針是標(biāo)準(zhǔn)的C/C++的回調(diào)函數(shù)的使用解決方案,本身提供了很大的靈活性。

#include <iostream>

// 聲明一個(gè)compute函數(shù)指針,函數(shù)參數(shù)為兩個(gè)int型,返回值為int型
int (*compute)(int, int);

int max(int x, int y) { return x >= y ? x : y; }
int min(int x, int y) { return x <= y ? x : y; }
int add(int x, int y) { return x + y; }
int multiply(int x, int y) { return x * y; }

// 一個(gè)包含函數(shù)指針作為回調(diào)的函數(shù)
int compute_x_y(int x, int y, int(*compute)(int, int))
{
  // 調(diào)用回調(diào)函數(shù)
  return compute(x, y);
}

int main(void) 
{
  int x = 2; 
  int y = 5;
  std::cout << "max: " << compute_x_y(x, y, max) << std::endl; // max: 5
  std::cout << "min: " << compute_x_y(x, y, min) << std::endl; // min: 2
  std::cout << "add: " << compute_x_y(x, y, add) << std::endl; // add: 7
  std::cout << "multiply: " << compute_x_y(x, y, multiply) << std::endl; // multiply: 10

  // 無(wú)捕獲的lambda可以轉(zhuǎn)換為同類(lèi)型的函數(shù)指針
  auto sum = [](int x, int y)->int{ return x + y; };
  std::cout << "sum: " << compute_x_y(x, y, sum) << std::endl; // sum: 7

  getchar();
  return 0;
}

Lambda函數(shù)

Lambda函數(shù)定義

Lambda函數(shù),又可以稱(chēng)為L(zhǎng)ambda表達(dá)式或者匿名函數(shù),在C++11中加入標(biāo)準(zhǔn)。定義形式如下:

[captures] (params) -> return_type { statments;}

其中:

  • [captures]為捕獲列表,用于捕獲外層變量
  • (params)為匿名函數(shù)參數(shù)列表
  • ->return_type指定匿名函數(shù)返回值類(lèi)型
  • { statments; }部分為函數(shù)體,包括一系列語(yǔ)句

需要注意:

  • 當(dāng)匿名函數(shù)沒(méi)有參數(shù)時(shí),可以省略(params)部分
  • 當(dāng)匿名函數(shù)體的返回值只有一個(gè)類(lèi)型或者返回值為void時(shí),可以省略->return_type部分
  • 定義匿名函數(shù)時(shí),一般使用auto作為匿名函數(shù)類(lèi)型

下面都是有效的匿名函數(shù)定義

auto func1 = [](int x, int y) -> int { return x + y; }; 
auto func2 = [](int x, int y) { return x > y; }; // 省略返回值類(lèi)型
auto func3 = [] { global_ip = 0; }; // 省略參數(shù)部分

Lambda函數(shù)捕獲列表

為了能夠在Lambda函數(shù)中使用外部作用域中的變量,需要在[]中指定使用哪些變量。

下面是各種捕獲選項(xiàng):

  • [] 不捕獲任何變量
  • [&] 捕獲外部作用域中所有變量,并作為引用在匿名函數(shù)體中使用
  • [=] 捕獲外部作用域中所有變量,并拷貝一份在匿名函數(shù)體中使用
  • [x, &y] x按值捕獲, y按引用捕獲
  • [&, x] x按值捕獲. 其它變量按引用捕獲
  • [=, &y] y按引用捕獲. 其它變量按值捕獲
  • [this] 捕獲當(dāng)前類(lèi)中的this指針,如果已經(jīng)使用了&或者=就默認(rèn)添加此選項(xiàng)

只有l(wèi)ambda函數(shù)沒(méi)有指定任何捕獲時(shí),才可以顯式轉(zhuǎn)換成一個(gè)具有相同聲明形式函數(shù)指針

auto lambda_func_sum = [](int x, int y) { return x + y; }; // 定義lambda函數(shù)
void (*func_ptr)(int, int) = lambda_func_sum; // 將lambda函數(shù)賦值給函數(shù)指針
func_ptr(10, 20); // 調(diào)用函數(shù)指針

std::function函數(shù)包裝

std::function定義

std::function在C++11后加入標(biāo)準(zhǔn),可以用它來(lái)描述C++中所有可調(diào)用實(shí)體,它是是可調(diào)用對(duì)象的包裝器,聲明如下:

#include <functional>

// 聲明一個(gè)返回值為int,參數(shù)為兩個(gè)int的可調(diào)用對(duì)象類(lèi)型
std::function<int(int, int)> Func;

使用之前需要導(dǎo)入<functional>庫(kù),并且通過(guò)std命名空間使用。

其他函數(shù)實(shí)體轉(zhuǎn)化為std::function

std::function強(qiáng)大的地方在于,它能夠兼容所有具有相同參數(shù)類(lèi)型的函數(shù)實(shí)體。

相比較于函數(shù)指針,std::function能兼容帶捕獲的lambda函數(shù),而且對(duì)類(lèi)成員函數(shù)提供支持。

#include <iostream>
#include <functional>

std::function<int(int, int)> SumFunction;

// 普通函數(shù)
int func_sum(int a, int b)
{
  return a + b;
}

class Calcu
{
public:
  int base = 20;
  // 類(lèi)的成員方法,參數(shù)包含this指針
  int class_func_sum(const int a, const int b) const { return this->base + a + b; };
  // 類(lèi)的靜態(tài)成員方法,不包含this指針
  static int class_static_func_sum(const int a, const int b) { return a + b; };
};

// 仿函數(shù)
class ImitateAdd
{
public:
  int operator()(const int a, const int b) const { return a + b; };
};

// lambda函數(shù)
auto lambda_func_sum = [](int a, int b) -> int { return a + b; };

// 函數(shù)指針
int (*func_pointer)(int, int);

int main(void) 
{
  int x = 2; 
  int y = 5;

  // 普通函數(shù)
  SumFunction = func_sum;
  int sum = SumFunction(x, y);
  std::cout << "func_sum:" << sum << std::endl;

  // 類(lèi)成員函數(shù)
  Calcu obj;
  SumFunction = std::bind(&Calcu::class_func_sum, obj, 
    std::placeholders::_1, std::placeholders::_2); // 綁定this對(duì)象
  sum = SumFunction(x, y);
  std::cout << "Calcu::class_func_sum:" << sum << std::endl;

  // 類(lèi)靜態(tài)函數(shù)
  SumFunction = Calcu::class_static_func_sum;
  sum = SumFunction(x, y);
  std::cout << "Calcu::class_static_func_sum:" << sum << std::endl;

  // lambda函數(shù)
  SumFunction = lambda_func_sum;
  sum = SumFunction(x, y);
  std::cout << "lambda_func_sum:" << sum << std::endl;

  // 帶捕獲的lambda函數(shù)
  int base = 10;
  auto lambda_func_with_capture_sum = [&base](int x, int y)->int { return x + y + base; };
  SumFunction = lambda_func_with_capture_sum;
  sum = SumFunction(x, y);
  std::cout << "lambda_func_with_capture_sum:" << sum << std::endl;

  // 仿函數(shù)
  ImitateAdd imitate;
  SumFunction = imitate;
  sum = SumFunction(x, y);
  std::cout << "imitate func:" << sum << std::endl;

  // 函數(shù)指針
  func_pointer = func_sum;
  SumFunction = func_pointer;
  sum = SumFunction(x, y);
  std::cout << "function pointer:" << sum << std::endl;

  getchar();
  return 0;
}

最后的輸出如下:

func_sum:7
Calcu::class_func_sum:27
Calcu::class_static_func_sum:7
lambda_func_sum:7
lambda_func_with_capture_sum:17
imitate func:7
function pointer:7

其中需要注意對(duì)于類(lèi)成員函數(shù),因?yàn)轭?lèi)成員函數(shù)包含this指針參數(shù),所以單獨(dú)使用std::function是不夠的,還需要結(jié)合使用std::bind函數(shù)綁定this指針以及參數(shù)列表。

std::bind參數(shù)綁定規(guī)則

在使用std::bind綁定類(lèi)成員函數(shù)的時(shí)候需要注意綁定參數(shù)順序:

// 承接上面的例子
SumFunction = std::bind(&Calcu::class_func_sum, obj, 
    std::placeholders::_1, std::placeholders::_2);
SumFunction(x, y);
  • 第一個(gè)參數(shù)為類(lèi)成員函數(shù)名的引用(推薦使用引用)
  • 第二個(gè)參數(shù)為this指針上下文,即特定的對(duì)象實(shí)例
  • 之后的參數(shù)分別制定類(lèi)成員函數(shù)的第1,2,3依次的參數(shù)值
  • 使用std::placeholders::_1表示使用調(diào)用過(guò)程的第1個(gè)參數(shù)作為成員函數(shù)參數(shù)
  • std::placeholders::_n表示調(diào)用時(shí)的第n個(gè)參數(shù)

看下面的例子:

// 綁定成員函數(shù)第一個(gè)參數(shù)為4,第二個(gè)參數(shù)為6
SumFunction = std::bind(&Calcu::class_func_sum, obj, 4, 6);
SumFunction(); // 值為 10

// 綁定成員函數(shù)第一個(gè)參數(shù)為調(diào)用時(shí)的第一個(gè)參數(shù),第二個(gè)參數(shù)為10
SumFunction = std::bind(&Calcu::class_func_sum, obj, std::placeholders::_1, 10);
SumFunction(5); // 值為 15

// 綁定成員函數(shù)第一個(gè)參數(shù)為調(diào)用時(shí)的第二個(gè)參數(shù),第一個(gè)參數(shù)為調(diào)用時(shí)的第二個(gè)參數(shù)
SumFunction = std::bind(&Calcu::class_func_sum, obj, std::placeholders::_2, std::placeholders::_1);
SumFunction(5, 10); // 值為 15

對(duì)于非類(lèi)成員對(duì)象,一般直接賦值即可,會(huì)自動(dòng)進(jìn)行轉(zhuǎn)換并綁定參數(shù),當(dāng)然也可以使用std::bind指定參數(shù)綁定行為;

#include <iostream>
#include <functional>

// 按照順序輸出x, y, x
void print_func(int x, int y, int z)
{
  std::cout << x << " " << y << " " << z << std::endl;
}
std::function<void(int, int, int)> Func;

int main()
{
  Func = std::bind(&print_func, 1, 2, 3);
  Func(4, 5, 6); // 輸出: 1 2 3

  Func = std::bind(&print_func, std::placeholders::_2, std::placeholders::_1, 3);
  Func(1, 2, 7); // 輸出: 2 1 3

  int n = 10;
  Func = std::bind(&print_func, std::placeholders::_1, std::placeholders::_1, n);
  Func(5, 6, 7); // 輸出: 5 5 10

  getchar();
  return 0;
}

需要注意:就算是綁定的時(shí)候指定了默認(rèn)參數(shù),在調(diào)用的時(shí)候也需要指定相同的參數(shù)個(gè)數(shù)(雖然不會(huì)起作用),否則編譯不通過(guò)。

關(guān)于回調(diào)函數(shù)

回調(diào)就是通過(guò)把函數(shù)等作為另外一個(gè)函數(shù)的參數(shù)的形式,在調(diào)用者層指定被調(diào)用者行為的方式。

通過(guò)上面的介紹,我們知道,可以使用函數(shù)指針,以及std::function作為函數(shù)參數(shù)類(lèi)型,從而實(shí)現(xiàn)回調(diào)函數(shù):

#include <iostream>
#include <functional>

std::function<int(int, int)> ComputeFunction;
int (*compute_pointer)(int, int);

int compute1(int x, int y, ComputeFunction func) {
  // do something
  return func(x, y);
}

int compute2(int x, int y, compute_pointer func)
{
  // do something
  return func(x, y);
}
// 調(diào)用方式參考上面關(guān)于函數(shù)指針和std::function的例子

以上兩種方式,對(duì)于一般函數(shù),簡(jiǎn)單lambda函數(shù)而言是等效的。

但是如果對(duì)于帶有捕獲的lambda函數(shù),類(lèi)成員函數(shù),有特殊參數(shù)綁定需要的場(chǎng)景,則只能使用std::function。

其實(shí)還有很多其他的實(shí)現(xiàn)回調(diào)函數(shù)的方式,如下面的標(biāo)準(zhǔn)面向?qū)ο蟮膶?shí)現(xiàn):

#include <iostream>

// 定義標(biāo)準(zhǔn)的回調(diào)接口
class ComputeFunc
{
public:
  virtual int compute(int x, int y) const = 0;
};

// 實(shí)現(xiàn)回調(diào)接口
class ComputeAdd : public ComputeFunc
{
public:
  int compute(int x, int y) const override { return x + y; }
};

int compute3(int x, int y, const ComputeFunc& compute)
{
  // 調(diào)用接口方法
  return compute.compute(x, y);
}

// 調(diào)用方法如下
int main()
{
  ComputeAdd add_func; // 創(chuàng)建一個(gè)調(diào)用實(shí)例
  int sum = compute3(3, 4, add_func); // 傳入調(diào)用實(shí)例
}

面向?qū)ο蟮姆绞礁屿`活,因?yàn)檫@個(gè)回調(diào)的對(duì)象可以有很復(fù)雜的行為。

以上三種方法各有各的好處,根據(jù)你需要實(shí)現(xiàn)的功能的復(fù)雜性,擴(kuò)展性和應(yīng)用場(chǎng)景等決定使用。

另外,這些函數(shù)類(lèi)型的參數(shù)可能為空,在調(diào)用之前,應(yīng)該檢查是否可以調(diào)用,如檢查函數(shù)指針是否為空。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • C語(yǔ)言判定一棵二叉樹(shù)是否為二叉搜索樹(shù)的方法分析

    C語(yǔ)言判定一棵二叉樹(shù)是否為二叉搜索樹(shù)的方法分析

    這篇文章主要介紹了C語(yǔ)言判定一棵二叉樹(shù)是否為二叉搜索樹(shù)的方法,結(jié)合實(shí)例形式綜合對(duì)比分析了C語(yǔ)言針對(duì)二叉搜索樹(shù)判定的原理、算法、效率及相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2018-08-08
  • C語(yǔ)言實(shí)現(xiàn)素因子分解

    C語(yǔ)言實(shí)現(xiàn)素因子分解

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)素因子分解,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • C++實(shí)現(xiàn)圖像壓縮的示例代碼

    C++實(shí)現(xiàn)圖像壓縮的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何使用C++實(shí)現(xiàn)圖像壓縮的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-12-12
  • C++使用動(dòng)態(tài)內(nèi)存分配的原因解說(shuō)

    C++使用動(dòng)態(tài)內(nèi)存分配的原因解說(shuō)

    這篇文章主要介紹了C++使用動(dòng)態(tài)內(nèi)存分配的原因解說(shuō),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • C++實(shí)現(xiàn)基于EASYX庫(kù)掃描線算法

    C++實(shí)現(xiàn)基于EASYX庫(kù)掃描線算法

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)基于EASYX庫(kù)掃描線算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • C++中的函數(shù)指針與函數(shù)對(duì)象的總結(jié)

    C++中的函數(shù)指針與函數(shù)對(duì)象的總結(jié)

    以下是對(duì)C++中的函數(shù)指針與函數(shù)對(duì)象的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以參考下
    2013-07-07
  • C++11之std::future對(duì)象的使用以及說(shuō)明

    C++11之std::future對(duì)象的使用以及說(shuō)明

    這篇文章主要介紹了C++11之std::future對(duì)象的使用以及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Qt自繪實(shí)現(xiàn)蘋(píng)果按鈕滑動(dòng)效果的示例代碼

    Qt自繪實(shí)現(xiàn)蘋(píng)果按鈕滑動(dòng)效果的示例代碼

    這篇文章主要介紹了Qt自繪實(shí)現(xiàn)蘋(píng)果按鈕滑動(dòng)效果的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 基于C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單五子棋游戲

    基于C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單五子棋游戲

    這篇文章主要為大家詳細(xì)介紹了基于C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單五子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C++ Boost PropertyTree解析INI文件詳解

    C++ Boost PropertyTree解析INI文件詳解

    Boost PropertyTree庫(kù)不僅可以解析JSON,XML格式,還可以直接解析INI格式文件。這篇文章就是為大家介紹一下如何通過(guò)Boost PropertyTree解析INI文件,需要的可以參考一下
    2022-01-01

最新評(píng)論