C++——参数绑定

一些STL算法要求我们使用一元函数,可是有些函数却不是一元的,C++提供了一项叫做函数绑定的技术

顾名思义,就是讲参数绑定到函数上,使一些非一元函数能够当作一元函数使用,准确的来说,不是哪些非一元函数本身能当做一元函数使用,而是一个名为bind的函数包装器能返回一个绑定过参数的函数对象。

bind是一个函数,也是一个函数包装器,定义在<functional>头文件中

简单的参数绑定

假设搜索第一个大于长度n的字符串,可以用find_if,但是其接受一个一元谓词,那就可以用bind包装函数将其变为一元谓词

演示

bool Find(const string &s,int a)
{
    return s.size()>=a;
}

int main()
{
    vector<string> vec {"hello","english","aaa","yes","C++"};
    auto i = find_if(vec.begin(), vec.end(),bind(Find,placeholders::_1,6));
    cout << *i;
}

运行结果

english 

bind(Find,placeholders::_1,6)

其中_1是一个占位参数,从1开始_n,说明了被包装过的函数对应传入到原来函数参数的顺序 

被定义在名称空间placeholders中,placeholders又被包含在namespace中,但如果不使用using声明还是要使用作用域解析符号来使用。 

使用方法

#include <bits/stdc++.h>

using namespace std;
//降序排列
bool is_Swap(const string & s1,const string & s2)
{
    return s1<s2;
}
int main()
{
    vector<string> vec {"hello","english","aaa","yes","C++"};
    sort(vec.begin(), vec.end(),bind(is_Swap,placeholders::_2,placeholders::_1));
    for_each(vec.begin(), vec.end(),[](const string &s){cout << s << endl; });
}

很容易发现bind函数是一个可变参数函数

主要作用就是讲函数进行包装以满足一些STL算法的需求。

有时候一些特殊的对象不能赋值,比如流对象。要用到ref或者cref函数,返回一个对象,包含给定的引用,此引用时可复制的。

ostream & print(ostream & os, const string & s,const char ch)
{
    cout << s << ch;
    return os;
}

int main()
{
    vector<string> vec {"hello","english","aaa","yes","C++"};
    for_each(vec.begin(), vec.end(),bind(print,ref(cout),placeholders::_1,'\n'));
}

 

 

### C++中动态绑定与静态绑定的概念及区别 #### 概念定义 在C++中,**绑定**指的是将函数调用与其具体实现进行关联的过程。这种过程分为两种形式:静态绑定和动态绑定。 - **静态绑定**是指在编译期间完成的方法或函数的绑定操作[^1]。它基于对象的静态类型来决定调用的具体方法或属性。 - **动态绑定**则是在运行时完成的方法或函数的绑定操作[^2]。它依据对象的实际动态类型来决定调用的具体方法或属性。 #### 主要区别 | 特性 | 静态绑定 | 动态绑定 | |-------------------|-------------------------------------|------------------------------------| | 绑定时间 | 编译期 | 运行期 | | 类型依赖 | 对象的静态类型 | 对象的动态类型 | | 实现方式 | 基于非虚函数 | 基于虚函数 | | 是否支持多态 | 不支持 | 支持 | ##### 静态绑定的特点 静态绑定发生在编译时期,因此其效率较高[^3]。所有的非虚函数都使用静态绑定机制,这意味着无论实际对象是什么类型的实例,只要声明时采用了某种类型,那么就会按照这个类型去查找并调用相应的成员函数或访问变量[^4]。 ```cpp class Base { public: void show() { std::cout << "Base"; } }; class Derived : public Base { public: void show() { std::cout << "Derived"; } }; int main(){ Base* b = new Derived(); b->show(); // 输出 "Base" } ``` 上述例子展示了即使 `b` 指向了一个 `Derived` 的实例,但由于 `show()` 是非虚函数,所以仍然调用了基类版本的方法。 ##### 动态绑定的特点 为了实现真正的面向对象编程中的多态特性,C++引入了虚拟表(vtable)以及虚函数这一概念。当某个类中的某些方法被标记为virtual之后,这些方法便具备了动态绑定的能力——即它们会在运行时刻根据当前对象的真实类型选择合适的重写版本执行。 ```cpp #include <iostream> using namespace std; class Animal{ public: virtual void speak(){ cout<<"Animal speaks"<<endl; } }; class Dog: public Animal{ public: void speak(){ cout<<"Dog Barks!"<< endl;} }; void makeSound(Animal &a){ a.speak(); } int main(){ Dog d; makeSound(d); // Output will be 'Dog Barks!' return 0; } ``` 在这个案例里,尽管参数传递给makeSound函数的形式是一个基础类别别的引用,但因为speak已经被设定成了一个虚函数,所以在最终输出的时候能够反映出传入实体所属派生类的行为特征。 #### 使用场景分析 - 如果应用程序设计不需要考虑子类扩展或者只需要固定逻辑处理的情况下,可以优先选用静态绑定以获得更好的性能表现; - 当存在继承关系并且希望父类接口能灵活映射至不同子类行为模式下,则应该利用好动态绑定技术达成目的。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值