C++中的可调用对象

  在C++中,常常会利用函数来简化程序流程。函数的存在使得C++整体更加“模块化”,因而也使得代码可读性大大提高。

  在C++程序中,常常会很灵活地调用函数来实现不同的功能与目的(函数重载、继承多态等等)。在一些情况下,可以传入类似函数一样的可调用对象,使得这一用法更加强大。

  下面是简单整理的几种调用方法:

  首先,给定一个共同的前提。标准库提供了排序算法来帮助设计者实现基础的排序,如果设计者希望更加灵活地按照自定义的排序方式来调用标准函数进行排序,就可以在标准排序函数中,传入一个指向自定义的可调用对象即可。

  下面,就依照这个前提,实现对一组int元素的升序排序,这里使用std::vector<int>来进行装载,即目标是让这个vector中的元素按照升序重新排列。

  1. 使用Lambda:

    事实上,在C++中,Lambda表达式就可以理解成生成一个可调用函数,而且这个函数是inline的。当然,这里可以直接把它作为一个可调用对象来使用。

  2. 通过函数名直接调用自定义函数

    通过传入一个自定义函数的名字(编译器会自动将其转换成函数指针类型),可以达到直接调用该自定义函数的目的。

    首先,根据这个前提定义一个名为isLess的函数,就像这样:

    然后,直接传入这个函数的名字(isLess)即可:

  3. 传入指向自定义函数的函数指针

    类似于2,传入指向这个自定义函数的函数指针也可以调用这个可调用对象。

    当然,首先定义一个指向这个函数的函数指针:

    然后,就像调用函数一样,传入这个函数指针就可以了:

  4. 使用标准库bind函数来生成一个可调用对象,进而对其调用

    std::bind函数可以根据一个已定义的函数,生成一个可调用对象,这个可调用对象的传入参数列表可以自己定义与设计。更炫酷的是,这个参数列表不一定非要和被绑定的函数参数列表一致!

  5. 使用自定义的可调用对象

    或许这听起来有点儿意思,事实上的确如此。用户可自定义一个可调用对象,只需要重载这个对象的类的()符号。相信我,尽管C++的重载运算符算是比较复杂的操作,但其中乐趣无穷。

    这里,简单地定义一个需要的类(当然,我们需要的重点是这个类一定要重载()符号,毕竟这才是调用对象的重头戏):

    然后,在主调函数中,要实例化一个这个类的对象(所以才能称之为可调用“对象”嘛...),只需要简单地将这个对象看作是一个“可调用函数”就ok了!

  6. 使用标准库定义的可调用对象

    既然说到了自定义可调用对象,那么标准库中很可能已经有相关的基本实现了。标准库提供了标准库中很多类型的基本操作的可调用对象,很多时候,对于简单的内置类型,需要相关操作时只需要简单地调用标准库提供的可调用对象即可。

  以上就是简单地设计生成/调用可调用对象的几种方法,当然,有的时候不同的方法带来的效益可能不同,适时地使用相应的可调用对象可以极大地简化程序。

  下面附上上述所有方案的代码,包含的头文件以及实现文件,需要自己来写。当然,都是一些简单的操作,看官自行写一写就好。

 1 #include "modnar.h"
 2 
 3 #include "show.cpp"
 4 #include "random.cpp"
 5 
 6 bool isLess(const int &a, const int &b) {
 7     return a < b;
 8 }
 9 
10 class CompareObj {
11 public:
12     CompareObj() = default;
13     bool operator()(const int &a, const int &b) {
14         return a < b;
15     }
16 };
17 
18 int main(int argc, char *argv[]) {
19     std::vector<int> vec(20);
20     bool (*pf)(const int &, const int &) = isLess;
21     // You can also get "pf" like this:
22     // decltype(isLess) *pf = isLess;
23 
24     // Method1. Use Lambda expression.
25     modnar::get_rand_seq(vec);
26     std::sort(vec.begin(), vec.end(), 
27             [](const int &a, const int &b) { return a < b; });
28     modnar::show(vec);
29 
30     // Method2. Call a function by its name.
31     modnar::get_rand_seq(vec);
32     std::sort(vec.begin(), vec.end(), isLess);
33     modnar::show(vec);
34 
35     // Method3. Call a function by using a function pointer to it.
36     modnar::get_rand_seq(vec);
37     std::sort(vec.begin(), vec.end(), pf);
38     modnar::show(vec);
39 
40     // Method4. Use std::bind function to generate a callable object.
41     modnar::get_rand_seq(vec);
42     std::sort(vec.begin(), vec.end(), 
43             std::bind(isLess, std::placeholders::_1, std::placeholders::_2));
44     modnar::show(vec);
45 
46     // Method5. Use a self-defined callable object.
47     CompareObj *comp = new CompareObj();
48     modnar::get_rand_seq(vec);
49     std::sort(vec.begin(), vec.end(), *comp);
50     modnar::show(vec);
51 
52     // Method6. Use the callable object provided by standard library.
53     modnar::get_rand_seq(vec);
54     std::sort(vec.begin(), vec.end(), std::less<int>());
55     modnar::show(vec);
56 
57     return 0;
58 }
Main.cpp

  若有相关内容的想法与方法,以及对文章的建议与异议,请评论区分享你的idea,提前说声谢谢。

 

  @编辑于2019.3.8

posted @ 2019-03-08 23:07  Modnar  阅读(390)  评论(0编辑  收藏  举报