ToB企服应用市场:ToB评测及商务社交产业平台

标题: C++11 的继承学习 [打印本页]

作者: 立山    时间: 2024-9-9 11:46
标题: C++11 的继承学习
1.lambda 
我们如果想要给一个自定义的元素排序,那么应该怎么排呢
先举个例子:
  1. struct Goods
  2. {
  3.         string _name;  // 名字
  4.         double _price; // 价格
  5.         int _evaluate; // 评价
  6.         Goods(const char* str, double price, int evaluate)
  7.                 :_name(str)
  8.                 , _price(price)
  9.                 , _evaluate(evaluate)
  10.         {}
  11. };
  12. struct Comparepriceless
  13. {
  14.         bool operator()(const Goods& g1, const Goods& g2)
  15.         {
  16.                 return g1._price < g2._price;
  17.         }
  18. };
  19. int main()
  20. {
  21.         vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,
  22. 3 }, { "菠萝", 1.5, 4 } };
  23.         sort(v.begin(), v.end(), Comparepriceless());
  24. }
复制代码
这里的Comparepriceless(),这是在干什么呢:sort要接受的是一个函数,而我们现在Comparepriceless是一个类,所以是用它调用operator(),我们此时用的是仿函数,然后用匿名对象调用operator,但是不能用有名对象的operator(),这是因为你()要传参数,它必要的是如许的:如许才气调用到,但是我们仿函数会主动反过来调用

这是我们平常写的,如果学习了c++11的话我们有了新的写法,就是用lambda写 ,比较方便用于多个差别种类的那种,有利之处类似于多态那种感觉。
   lambda表达式书写格式:[capture-list] (parameters) mutable -> return-type { statement     }     1. lambda表达式各部分说明     [capture-list] : 捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来     判断接下来的代码是否为lambda函数捕捉列表可以或许捕捉上下文中的变量供lambda     函数利用。     (parameters):参数列表。与普通函数的参数列表一致,如果不必要参数传递,则可以     连同()一起省略     mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量     性。利用该修饰符时,参数列表不可省略(纵然参数为空)。        ->returntype:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回        值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推        。        {statement}:函数体。在该函数体内,除了可以利用其参数外,还可以利用所有捕获        到的变量。        注意:        在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为        。因此C++11中最简单的lambda函数为:[]{}; 该lambda函数不能做任何事情。   
  1. int main()
  2. {
  3.         vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,
  4.                 3 }, { "菠萝", 1.5, 4 } };
  5.         for (auto e : v)
  6.         {
  7.                 cout << e._name << " ";
  8.         }
  9.         cout << endl;
  10.         sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2)->bool
  11.                 {
  12.                         return g1._price > g2._price;
  13.                 });
  14.         for (auto e : v)
  15.         {
  16.                 cout << e._name << " ";
  17.         }
  18. return 0;
  19. }
复制代码
 
2接着我们要具体写一下lambda的各种情况以及利用情况
  1. int main()
  2. {
  3.         //最简单的lambda
  4.         [] {};//从中我们可以知道 参数列表 返回类型 都是可以省略的
  5.         int a = 10, b = 20, c = 30;
  6.         //省略返回类型:
  7.         auto d = [](int x, int y) {return x + y; };
  8.         cout << d(a, b) << endl;
  9.        
  10.         //使用lambda 对于参数的两种方式
  11.         auto e = [](int x, int y)->int//传参
  12.                 {
  13.                         return x + y;
  14.                 };
  15.         cout << e(a, b)<<endl;
  16.         auto la=[a, b]()->int//追踪 追踪到的是原变量的拷贝,具有cosnt性质
  17.                 {
  18.                         return a + b;
  19.                 };
  20.         cout << la() << endl;
  21.         //全追踪
  22.         auto f = [=] {return a + b + c; };
  23.         cout << f() << endl;
  24.         //全追踪 改变常量 只改变拷贝,实际改变需要引用
  25.         auto g = [=]()mutable {a++; };
  26.         //引用追踪 因为引用符号和取地址符号重复了,
  27.         auto m = [&] {a++, b++, c++; };
  28.         m();
  29.         cout << a << " " << b << " " << c << endl;
  30. }
复制代码
  3捕获列表说明     捕捉列表描述了上下文中那些数据可以被lambda利用,以及利用的方式传值照旧传引用。     [var]:表示值传递方式捕捉变量var     [=]:表示值传递方式捕获所有父作用域中的变量(包罗this)     [&var]:表示引用传递捕捉变量var     [&]:表示引用传递捕捉所有父作用域中的变量(包罗this)     [this]:表示值传递方式捕捉当前的this指针     注意:     a. 父作用域指包罗lambda函数的语句块     b. 语法上捕捉列表可由多个捕捉项组成,并以逗号分割。     比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量     [&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量     c. 捕捉列表不答应变量重复传递,否则就会导致编译错误。     比如:[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a重复     d. 在块作用域以外的lambda函数捕捉列表必须为空。        e. 在块作用域中的lambda函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者        非局部变量都       会导致编译报错。        f. lambda表达式之间不能相互赋值,纵然看起来类型相同       4:lambda与 函数对象(仿函数)       仿函数:   在类中重载了operator()运算符的类对象。      
  1. class Rate
  2. {
  3. public:
  4.         Rate(double rate) : _rate(rate)
  5.         {}
  6.         double operator()(double money, int year)
  7.         {
  8.                 return money * _rate * year;
  9.         }
  10. private:
  11.         double _rate;
  12. };
  13. int main()
  14. {
  15.         // 函数对象
  16.         double rate = 0.49;
  17.         Rate r1(rate);
  18.         r1(10000, 2);
  19.         // lamber
  20.         auto r2 = [=](double monty, int year)->double {return monty * rate * year;
  21.                 };
  22.         r2(10000, 2);
  23.         return 0;
  24. }
复制代码
  
    二:function包装器
   function包装器 也叫作适配器。C++中的function本质是一个类模板,也是一个包装器。   
  1. #include<functional>
  2. struct Functor
  3. {
  4. public:
  5.         int operator() (int a, int b)
  6.         {
  7.                 return a + b;
  8.         }
  9. };
  10. int f(int a, int b)
  11. {
  12.         return a + b;
  13. }
  14. class Plus
  15. {
  16. public:
  17.         static int plusi(int a, int b)//没有 this
  18.         {
  19.                 return a + b;
  20.         }
  21.         double plusd(double a, double b)
  22.         {
  23.                 return a + b;
  24.         }
  25. };
  26. int main()
  27. {
  28.         //包装三种 函数指针 仿函数 lambda
  29.         function<int(int, int)> f1 = f;
  30.         function<int(int, int)>f2 = Functor();
  31.         function<int(int, int)> f3 = [](int x, int y) {return x + y; };
  32. }
复制代码
让我们以一道题看看function 的作用:LCR 036. 逆波兰表达式求值 - 力扣(LeetCode)
  1. class Solution {
  2. public:
  3.     int evalRPN(vector<string>& tokens)
  4.     {
  5.         stack<int> st;
  6.         map<string,function<int(int,int)>> m =
  7.         {
  8.             {"+",[](int x,int y)->int{return x+y;}},
  9.             {"-",[](int x,int y)->int{return x-y;}},
  10.             {"*",[](int x,int y)->int{return x*y;}},
  11.             {"/",[](int x,int y)->int{return x/y;}}
  12.         };
  13.         for(auto& e:tokens)
  14.         {
  15.             if(m.count(e))
  16.             {
  17.                 int front=st.top();
  18.                 st.pop();
  19.                 int second=st.top();
  20.                 st.pop();
  21.                 int ret=m[e](second,front);
  22.                  st.push(ret);
  23.             }
  24.             else
  25.             {
  26.                  st.push(stoi(e));
  27.             }
  28.         }
  29.         return st.top();
  30.     }
  31. };
复制代码
function 对非静态成员函数封装的时间,要思量隐含的tiis指针 、
可以传指针,也可以传对象:原因是function不是直接传参调用函数的,它会把函数指针看成成员变量存储,然后再用对象或者指针来调用对应的函数,它会主动反过来调用。
  1. class Plus
  2. {
  3. public:
  4.         static int plusi(int a, int b)//没有 this
  5.         {
  6.                 return a + b;
  7.         }
  8.         double plusd(double a, double b)
  9.         {
  10.                 return a + b;
  11.         }
  12. };
  13. int main()
  14. {
  15.         //function 主要是为了调用函数,就是封装函数,方便每次使用,
  16.         //一共有三个 :仿函数 函数指针 lambda ,每次使用function的时候都需要传函数指针 不如用bind 也是调用函数
  17.        
  18.         function<double(Plus, double, double)> f6 = &Plus::plusd;//封装的是函数指针
  19.         function<double(Plus*, double, double)> f7 = &Plus::plusd;
  20.         //传的是对象 分为有名对象 匿名对象两种都可以传递
  21.         cout << f6(Plus(), 1.1, 1.1) << endl;
  22.         Plus pd;
  23.         cout << f7(&pd, 1.1, 1.1) << endl;
  24. }
复制代码

 三:bind
   std::bind函数定义在头文件中,是一个函数模板,它就像一个函数包装器(适配器)接受一个可     调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。一般而     言,我们用它可以把一个原本接收N个参数的函数fn,通过绑定一些参数,返回一个接收M个(M     可以大于N,但这么做没什么意义)参数的新函数。同时,利用std::bind函数还可以实现参数顺     序调整等操作。      bind 本质返回的一个仿函数对象
     调整参数顺序(不常用)
     _1代表第一个实参
     _2代表第二个实参
     ...  
  1. using placeholders::_1;
  2. using placeholders::_2;
  3. using placeholders::_3;
  4. int Sub(int a, int b)
  5. {
  6.         return (a - b) ;
  7. }
  8. int SubX(int a, int b, int c)
  9. {
  10.         return (a - b - c) ;
  11. }
  12. int main()
  13. {
  14.         auto a = bind(Sub, _1, _2);
  15.         cout << a(10, 20) << endl;
  16.         // 调整参数个数 (常用)
  17.         auto b = bind(Sub, 100, _1);//固定一个值 _1永远表示第一个你要传给的值,不是固定第一个
  18.         cout << b(20) << endl;;
  19.        
  20.         auto c = bind(Sub, _1, 100);
  21.         cout << c(20) << endl;
  22.         auto d = bind(SubX, _1, _2, _3);
  23.         cout << d(10, 20, 30) << endl;
  24.         auto e = bind(SubX, 100, _1, _2);
  25.         cout << e(20, 30) << endl;
  26.        
  27.         auto f = bind(SubX, _1, 100, _2);
  28.         cout << e(20, 30) << endl;
  29.         return 0;
  30. }
复制代码
最常用的就是用调整参数个数,还有就是调整参数顺序

_1 ,_2这种表示你开始传参(也就是除了那些固定的值的)的第一个,开始传参之后的第二个
还有就是要注意function 和bind不一样的区别,function要传有名对象,匿名对象或者有名对象的指针,bind传的函数指针并不用加括号,但是function在传匿名对象时间加了括号,注意括号的利用

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4