c++ 學習之 可調用對象

c++ 學習之 可調用對象

前言

c++中,在使用一些基於範圍的模板函數時,常常需要我們傳入一個可調用對象,以指明我們需要對範圍中的每個元素進行怎樣的處理。在thread的初始化中也需要傳入可調用對象來作爲線程的入口函數。可調用對象也可以作爲回調函數使用。可調用對象大概有這麼幾種:普通函數 ,類成員函數,類靜態函數,仿函數,函數指針,lambda表達式,std::function。下面給大家進行簡單的介紹。

正文

1.普通函數
普通函數大家最熟悉不過了,我們常常以定義函數的方式,來講某一段程序封裝在一起,來實現某一特定的功能。以下這種就是普通函數:

#include<stdio.h>
int Add(int a,Int b)
{
   return a+b;
}
int main()
{
   printf("%d\n",Add(1,3));
}

我們通過調用Add函數來得到兩個整數的相加結果。

2.類成員函數
類中定義的函數有兩種,一種是類靜態函數,另一種是類成員函數。不像類成員變量,兩者都有真實的地址。只不過類成員函數中隱含了this指針,也就是說可以在可以在函數內部隱式或顯式的使用this指針來調用類的非靜態成員。並且類成員函數必須依附於類對象使用,也就是說,在沒有對象實例的前提下,是無法通過函數地址使用該函數的

#include<stdio.h>
class A
{
public: 
  int a ;
  A(int a)
  {
   this->a =a ;
  }
  void fun()
  {
  printf("%d\n",a);
  }

};
int main()
{
  A a(10);
  a.fun();
  //A::fun();錯誤用法!!!
}

輸出結果:10

3.類靜態函數
上文說到的類中兩種函數,類靜態函數就是另一種。它與類成員函數最大的不同,就是它不可以調用類中的非靜態成員,也不可以使用this指針,但是可以不用創建類對象,直接通過函數地址調用。

#include<stdio.h>
class A
{
  public:
   static int a;
   static int Add(int b)
   {
    return A::a + b;
   }
};
int A::a =1;
int main()
{
    printf("%d\n",A::Add(2));
}

輸出結果 : 3
可以看到,我們沒有創建類的對象,通過直接使用類中的靜態函數Add得到類中的靜態成員a和2的和。

4.仿函數
通過在類內定義運算符重載函數,用類實現函數調用。

#include<stdio.h>
class A
{
 public:
   int operator()(int a,int b)
   {
    return a+b;
   }
};
int main()
{
   A a;
   printf("%d\n",a(1,2));
}

輸出結果 : 3
通過在類內部重載(),用類模擬函數的調用。

5.函數指針
函數指針大家並不陌生,我們使用回調函數可以通過函數指針來實現。下面舉個例子吧。

#include<stdio.h>
typedef int(*P)(int ,int);
int Add(int a,int b)
{
 return a+b;
}
int fun(int p (int,int),int a,int b)
{
 return  p(a,b);
}
int main()
{
 P pAdd = Add;
 int a =1;
 int b =2;
 printf("%d\n", fun(pAdd, a, b));
}

輸出結果 :3
雖然這個例子有點牽強,但是意在理解嘛,就是讓大家明白,函數指針的使用。往往很多地方需要這樣傳入一個函數指針作爲參數,這樣使用就是避免不了的了。其實也可以用函數名作爲參數

6.lambda表達式

lambda 表達式是一種匿名函數,即沒有函數名的函數,通常情況下,lambda函數的語法定義爲:
[capture] (parame) mutable ->return-type {statement}
其中:
[captures]爲捕獲列表,用於捕獲外層變量
(parame)爲匿名函數參數列表
mutable修飾符可以取消返回值的常量性
return-type爲返回值類型
{statement}爲函數體
通常情況下:
* 可以用auto來定義
* 若沒有參數,(parame)可以省略;
* 在默認的情況下,lambda函數總是返回一個const,而當我們在參數列表後面註明了“mutable”關鍵字之後,則可以取消其常量性質,當我們使用mutable時,(parame)不可以省略,即便參數爲空(mutable可以省略);
* return-type可以省略。
* [captures]捕獲項可以有0項或多項:
[] 不捕獲任何變量
[&] 捕獲外部作用域中所有變量,並作爲引用在匿名函數體中使用
[=] 捕獲外部作用域中所有變量,並拷貝一份在匿名函數體中使用
[&, x] x按值捕獲. 其它變量按引用捕獲
[=, &y] y按引用捕獲. 其它變量按值捕獲
[this] 捕獲當前類中的this指針,如果已經使用了&或者=就默認添加此選項

*只有lambda函數沒有指定任何捕獲時,纔可以顯式轉換成一個具有相同聲明形式函數指針

#include<stdio.h>
int main()
{
 int a = 1;
 int b = 2;
 auto Swap = [&]() {int temp = a; a = b; b = temp; };
 Swap();
 printf("%d %d\n", a, b);
}

通過匿名函數以引用的方式捕獲a,b,在函數中交換a與b的值。
注意,匿名函數在c++ 11 中是inline(內聯)的

7.std::function
std::function 可以用來描述C++中的可調用實體,它可以兼容所有具有相同參數類型的函數實體。需要引入<functional>頭文件,聲明方式如下:
std::function<Type(type1,type2)> name
下面舉幾個其他可調用對象轉換爲std::function的例子:

#include<stdio.h>
#include<functional>
std::function<void(int, int)> Function;
//普通函數
void fun(int a,int b)
{
 printf("普通函數:%d\n", a + b);
}
void fun2(int a, int b)
{
 printf("函數指針:%d\n", a + b);
}
class A
{
public:
 //類成員函數
 void fun1(int a, int b)
 {
  printf("類成員函數:%d\n", a + b);
 }
 //靜態成員函數
 static void fun2(int a, int b)
 {
  printf("靜態成員函數:%d\n", a + b);
 }
 //仿函數
 void operator ()(int a, int b)
 {
  printf("仿函數(類對象):%d\n", a + b);
 }
};
int main()
{
  int a =1;
  int b =2;
  Function = fun;
  Function(a,b);
 
  void (*p)(int,int) = fun2;
  Function = p;
  Function(a,b);
 
  A c;
  Function = std::bind(&A::fun1,c,std::placeholders::_1,std::placeholders::_2);  
  Function(a,b);


 Function  = &A::fun2;
 Function(a,b);

  A d;
  Function = d;
  Function(a,b); 

  auto lam = [](int a,int b){ printf("lambda表達式:%d\n",a+b);};
  Function = lam;
  Function(a,b);
}

其中需要注意對於類成員函數,因爲類成員函數包含this指針參數,所以需要結合使用std::bind函數綁定this指針以及參數列表。
上面例子中:
Function = std::bind(&A::fun1,c,std::placeholders::_1,std::placeholders::_2);
*第一個參數爲類成員函數名的引用
*第二個參數爲this指針上下文,即特定的對象實例
*使用std::placeholders::_1表示使用調用過程的第1個參數作爲成員函數參數,std::placeholders::_n表示調用時的第n個參數。

Function = std::bind(&A::fun1,c,std::placeholders::_1,10);
Function(5);

輸出結果 15

Function = std::bind(&A::fun1,c,510);
Function();

輸出結果 15

Function = std::bind(&A::fun1,c,std::placeholders::_2,std::placeholders::_1);
Function(5,10);

輸出結果 15
這樣的參數進去,a = 10, b = 5。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章