bind和多态

来源:互联网 发布:淘宝隐形眼镜可靠吗 编辑:程序博客网 时间:2024/06/11 17:22
定义一个函数为虚函数,不代表函数为不被实现的函数,定义它为虚函数是为了允许用基类的指针来调用子类的这个函数
定义一个函数为纯虚函数,才代表函数没有被实现,定义他是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数。



===================================================>

C++支持两种多态性:编译时多态性,运行时多态性。
a、编译时多态性:通过重载函数实现
b、运行时多态性:通过虚函数实现。
C++允许在同一范围中声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同,即函数的参数列表不同,也就是说用同一个运算符完成不同的运算功能。这就是重载函数C++允许在同一范围中声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同,即函数的参数列表不同,也就是说用同一个运算符完成不同的运算功能。这就是重载函数

C++用虚函数实现多态

父类里定义了虚函数

子类重写虚函数
========================================================》》》》

C++深入理解虚函数
面向对象的三大特征:
封装++++多态++++++继承

1,普通虚函数
2,虚析够函数
3,纯虚函数
4,抽象类
5,接口类
6,隐藏VS覆盖
7,隐藏与覆盖之间的关系
8,早绑定和晚绑定
9,虚函数表



什么是多态:
静态多态VS动态多态

a,静态多态也叫做早绑定:他们函数名相同,参数个数不同,一看就是互为重载的两个函数
b,动态多态也叫做晚绑定:可见动态多态是以封装和继承为基础的


+++++++++++++++++++++++++++++++++++++++++++++++++++++++
virtual在函数中的使用规则:
1,普通函数不能是虚函数,也就是说这个函数必须是某一个类的成员函数,
不可以是一个全局函数,否则会导致编译错误
2,静态函数不能是虚函数,static成员函数是和类同生共处的,他不属于任何
对象,使用virtual也将导致错误
3,内联函数不能是虚函数,如果修饰内联函数,如果内联函数被virtual修饰,
计算机会忽略inline使他变成纯粹的虚函数
4,构造函数不能是虚函数,否则会出现编译错误

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

什么是函数指针
指针指向对象称为对象指针,指针除了指向对象还可以指向函数。
函数的指针和普通的指针本质是一样的,也是由四个基本的内存单元组成,
存储着内存的地址,这个地址就是函数的首地址。



多态的实现原理:
虚函数表指针:类中除了定义的函数成员,还有一个成员是虚函数表指针
(占4个基本内存单元),这个指针指向一个虚函数表的起始位置,这个类会与
类的定义同时出现,这个表存放着该类的虚函数指针,调用的时候可以找到
该类的虚函数表指针,通过虚函数表指针找到虚函数表,通过虚函数表的偏移
找到函数的入口地址,这个地址就是函数的首地址


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
函数的覆盖和隐藏
父类和子类出现同名函数称为隐藏

    父类对象.函数函数名(...);     //调用父类的函数
    子类对象.函数名(...);           //调用子类的函数  
    子类对象.父类名::函数名(...);//子类调用从父类继承来的函数。

父类和子类出现同名虚函数称为覆盖
父类指针=new 子类名(...);父类指针->函数名(...);//调用子类的虚函数。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

虚析构函数的实现原理
虚析构函数的特点
当我们在父类中通过virtual修饰析构函数之后,通过父类指针指向子类对象,
通过delete接父类指针就可以释放掉子类对象
执行完子类的析构函数就会执行父类的析构函数
原理:
如果父类当中定义了虚析构函数,那么父类的虚函数表当中就会有一个父类的
虚析构函数的入口指针,指向的是父类的虚析构函数,子类虚函数表当中也会
产生一个子类的虚析构函数的入口指针,指向的是子类的虚析构函数,这个时候
使用父类的指针指向子类的对象,delete接父类指针,就会通过指向的子类的对象
找到子类的虚函数表指针,从而找到虚函数表,再虚函数表中找到子类的虚析构函数
,从而使得子类的析构函数得以执行,子类的析构函数执行之后系统会自动执行父类
的虚析构函数。这个是虚析构函数的实现原理。



+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

含有纯虚函数的类被称为抽象类






不支持C++11的编译器。
boost库里面最值得使用的是bind,function,shared_ptr等




在c++11之前,要绑定某个函数、函数对象或者成员函数的不同参数
值需要用到不同的转换器,如bind1st、bind2nd、fun_ptr、mem_fun和
mem_fun_ref等.在c++11中,绑定参数的方法得以简化.c++11提供了"一站
式"绑定模板bind,其用法为:

#include <functional>
std::bind(待绑定的函数对象/函数指针/成员函数指针,参数绑定值1,参数绑定值2,...,参数绑定值n);



bind的第一个参数是待绑定的函数对象或者函数指针,之后跟随多个参数以设定
待绑定函数的参数绑定方式。待绑定函数有多少个参数,则bind后便需要多少个
参数以一一声明其参数的绑定方法 ,当参数绑定为某一固定值时,则其对应
参数绑定值可以使一个一个变量或常量。当需要将参数与绑定所生成的函数对象的
某个参数相关联,则需要用到标准中预定义的几个常量_1、_2、_3等,这些常量
声明在std::placeholders命名空间内





绑定成员函数的注意点:
在将一个R (T::*ptr)(Arg0,Arg1,...)形式的成员函数指针ptr用bind绑定
参数时,bind的第一个绑定的参数是成员函数的调用者,随后跟随成员函数
的参数绑定方式,例如bind(ptr,a,b,c)将会调用a.*ptr(b,c)。当采用
_n常量将首参数与函数对象的参数相关联时,所生成的函数对象自动可接受
T类型的引用及指针类型,无需在进行封装,但要想调用外部数据的成员函数,
还需要ref(),cref()来包装或者绑定一个对该变量的指针









#include <functional>
#include <iostream>

//一个自定义的整数类
struct integer{
      int i;
      integer(int i):i(i){}
      void incr_by(int j){ i+=j;}
};

void mem_func_sample(){
     integer x(0);    //x.i=0;
     integer *y=&x;   //y指向x
     using namespace std::placeholders;
     using namespace std;
     
     auto f0=bind(&integer::incr_by,_1,_2);
     f0(x,2);     //x.incr_by(2)
     cout<<x.i<<endl;
     
     f0(y,2);         //y->incr_by(2)
     cout<<x.i<<endl;   //x.i=4
     
     auto f1=bind(&integer::incr_by,x,_1);
     f1(2);   //x在f1的副本.incr(2)
     cout<<x.i<<endl;  x.i=4;
     
     auto f2=bind(&integer::ince_by,ref(x),_1);
     f2(2);   //x.incr_by(2)
     cout<<x.i<<endl;       //x.i=6;
     
     auto f3=bind(&integer::incr_by,&x,_1);
     f3(2);   //(&x)->incr_by(2)
     cout<<x.i<<endl;  //x.i=8
     
     //利用mem_fn将成员函数转换为函数对象
     auto f4=mem_fn(&integer::incr_by);
     f4(x,2);  
     cout<<x.i<<endl;//x.i=10;
     f4(y,2);   
     cout<<x.i<<endl;//x.i=12
     
     
}

上例中用不同的方式为integer类的incr_by成员函数绑定参数.
对于所得的函数对象f0,由于bind的首参数与f0的第一个参数相
关联,f0将自动以integer为首参数类型,所以f0(x,2)实际调用
了x.incr_by(2),使得x的i值增加2;另外f0也自动支持integr指针,
所以调用f0(y,2)相等于执行了y->incr_by(2),同样使得x的i值增加2。
而f1的调用是x在f1内的副本,不会影响x的状态.只有如f2或f3那样绑
定x才会真正调用x的成员函数.
原创粉丝点击