第8章 函数探索

第8章   函数探索
8.1C++内联函数
(1)常规函数的执行过程:
        执行到函数调用指令时,程序将在函数调用后立即存储该指令的内存地址,并将函数的参数复制
        到堆栈(为此保留的内存块),跳到标记函数起点的内存单元,执行函数代码(也许还将返回值          
	放入到寄存器中),然后跳回到地址被保存的指令处。
(2)内联函数:
        [1]代码执行时间短,函数经常被调用
        [2]定义:编译器将使用相应的函数代码替换函数调用,程序无需再跳到另一个位置处执行,在跳           回来              
        [3]如何选择:
        如果执行函数代码的时间比处理函数调用机制的时间长,则节省时间将只占整个过程的很小一部
              ----                    ------  
        分
        [4]内联函数不能递归
        [5]请求将函数作为内联函数时,编译器并不一定会满足这种要求
        [6]内联与宏
                  #include<iostream>
		  #define SQUARE(x) ((x)*(x))
                  inline double square(double x) {return x*x;}
                  using namespace std;

                  int main()
                  {
                      int c=2;
                      //cout<<c++*c++<<endl;
                      cout<<SQUARE(c++)<<endl;    //c++*c++
                      cout<<c<<endl;              //c递增两次,宏不能按值传递
                      int d=2;
                      cout<<square(d++)<<endl;//d递增一次
                      cout<<d<<endl;
                      return 0;
                   }
8.2引用变量
8.2.1
(1)典型用途:作为函数参数,结构和对象的参数
(2)必须声明引用变量是初始化
(3)引用更接近const指针,必须在创建时初始化
     int &rodents = rats;
     int * const pr = &rats;
     #include<iostream>

     using namespace std;
     int main()
     {
         int rats = 101;
         int &rodents = rats;
         cout<<"rat = "<<rats;
         cout<<",rodents = "<<rodents<<endl;
         cout<<"rats address = "<<&rats;
         cout<<",rodents address = "<<&rodents<<endl;
         int bunnies=50;
         rodents = bunnies;  //可以通过初始化声明来设置引用,但不能通过赋值来设置
         cout<<"bunnies = "<<bunnies;
         cout<<",rats = "<<rats;
         cout<<",rodents = "<<rodents<<endl;
         cout<<"bunnies address = "<<&bunnies;
         cout<<",rats address = "<<&rats;
         cout<<",rodents address = "<<&rodents<<endl;
         return 0;
     }
     int rats = 101;
     int * pt = &rats;
     int &rodents = &pt;
     int bunnies = 50;
     pt = &bunnies;
     rodents 引用的还是rats
8.2.2
(1)按值传递和按引用传递
(2)函数调用使用实参初始化形参,因此函数的引用参数被初始化为函数调用传递的
8.2.3
实参的类型与引用参数类型不匹配,但可被转换为引用类型,程序将创建一个正确类型的临时变量
(1)什么时候创建临时变量?(如果引用参数是const)
          [1]实参的类型正确,但不是左值
          [2]实参的类型不正确,但可以转换为正确的类型
     什么是左值?P271
          可以被引用的数据对象,如:变量,数组元素,结构成员,引用,???解除引用的指针???
          非左值,如:字面变量(5.0)(用引号括起的字符串除外)
(2)将引用参数声明为常量数据的引用的理由:
          [1]使用const可以避免无意中修改数据的编程错误;
          [2]使用const使函数能够处理const和非const实参,否则将只能接收非const数据;
          [3]使用const引用使函数能够正确生成并使用临时变量。
8.2.4
(1)返回值为引用:
             返回引用的函数实际上是被引用变量的别名
(2)注意问题:
             避免返回函数终止时不再存在的内存单元引用(返回一个指向临时变量的引用)   
     解决方法:
            [1]返回一个作为参数传递给函数的引用
            [2]???用new来分配新的存储空间
                        const free_throws & clone(free_throws &ft)
                        {
				free_throws *pt;
                                *pt = ft;
                                return *pt;
                        }
			free_throws &jolly = clone(three);
(3)const用于引用返回类型
          返回const引用是不可修改的左值,
            
8.2.7何时使用引用参数
8.3
默认参数:当函数调用中省略了实参时自动调用的一个值
                #include<iostream>
                #include<cstring>
                using namespace std;


                char *left(char *str,int n=1)
                {
                    if(n<0)//用户要求字符数目为负
                    {
                        n=0;
                    }
                    //用户要求字符数目可能多于字符串包含的字符数
                    int len=strlen(str);
                    n=n<len?n:len;
                    char *p=new char [n+1];
                    int i;
                    for(i=0;i<n;i++)
                    {
                        p[i]=str[i];
                    }
                    p[i]='\0';
                    return p;
                }
                int main()
                {
                    char str[1024];
                    int n;
                    while(cin>>str/*>>n*/)
                    {
                        cout<<left(str/*,n*/132323)<<endl;
                    }
                    return 0;
                }

8.4
(1)函数重载:名称相同,参数数目和/或参数类型不同和/或返回类型不同
              类型引用和类型本身视为同一个特征标
(2)一个数字左边几位
              unsigned long left(unsigned long num,unsigned ct)
              {
			unsigned digits = 1;
			unsigned logn n = num;
    			if(ct == 0||num == 0)
			{
				return 0;
			}
			while(n/=10)
			{
				digits++;
			}
			if(digits>ct)
			{
				ct = digits - ct;
 				while(ct--)
				{
					num/=10;
				}
				return num;
			}
			else
			{
				return num;
			}
	       } 
(3)何时使用?
		P289
  		函数基本上执行相同的任务,但使用不同形式的数据时
		使用一个但默认参数的函数简单些
8.5函数模板
(1)		template<typename T>
		void Swap(T &a,T&b)
		{
			T temp;
			temp = a;
			a = b;
			b = temp;	
		}
		template<typename T>
		void Swap(T a[],T b[],int n)
		{
			T temp;
			for(int i=0;i<n;i++)
			{
				temp = a[i];
				a[i] = b[i];
				b[i] = temp;
			}
		}
(2)显示具体化  template <typename T>         
		void Swap(T &,T &)           --模板函数
	        void Swap(job &,job &)       --非模板函数
		当编译器找与函数调用匹配的具体化定义时,将使用该定义,而不再寻找模板
		struct job
		{
			char name[40];
			double salary;
			int floor;
		};
		template<>void Swap<job>(job &j1,job &j2)    --具体化原型
		{
			double t1;
			int t2;
			t1= j1.salary;
			j1.salary=j2.salary;
			j2.salary=t1;
			t2=j1.floor;
			f1.floor=j2.floor;
			j2.flooe=t2;
		}
		template<typename T>
		void Swap(T &a,T &b)
		{
			T temp;
			temp=a;
			a=b;
			b=temp;
		}
8.5.4
(1)编译器使用模板为特定类型生成函数定义时,得到函数模板的实例
(2)模板并非函数的定义,但是使用int的模板实例是函数定义
(3)隐式实例化:由于调用Swap()函数时提供了int
(4)显示实例化:直接命令编译器创建特定的实例
	template void Swap<int>(int,int);
		
(5)显示具体化template<>void Swap<int>(int&,int&);
	    template<>void Swap(int &,int &)
(6)试图在同一个文件(或转换单元)中使用同一种类型的显示实例化和显示具体化将出错
(7)显示实例化:template
     显示具体化:template<>
8.5.5
(1)指向非const数据的指针和引用优先于非const指针和引用参数列表
     const和非const之间的区别只适用于指针和引用指向的数据
      二义性错误:
                 struct blot {int a; char b[10]};
		 blot ink={25,"sports"};
		 recycle(ink);
		 void recysle(blot);
                 void recycle(const blot);
(2)一个完全匹配优先于另一个的另一种情况,非模板函数优先于模板函数(显示具体化)
(3)如果两个完全匹配的函数都是模板函数,则较具体的模板函数优先
                 struct blot {int a; char b[10]};
		 blot ink={25,"sports"};
		 recycle(&ink);           选#2
                 template<class Type> void recycle(Type t)       #1
		 template<class Type> void recycle(Type *t)      #2
                 两个隐式实例
                 recycle<blot*>(blot*)    #1
		 recycle<blot>(bloe *)    #2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值