C++学习:引用和函数的高级用法

C++学习:引用和函数的高级用法

  1. 引用的概念(引用和引用参数)
  2. 内联函数
  3. 默认参数的函数
  4. 函数重载
  5. 函数模板

    由于本人也是一位新的C++Coder,出于对C/C++的兴趣爱好,所以学习,这些也都是相关的学习笔记类的.如有写的不好或者不对的地方.求谅解.

引用的概念(引用和引用参数)

为什么要引入引用的概念:

C语言函数的参数传递
    按值传递,按值传递如果传递很大数据项,复制数据将导致较长的执行时间,所有在C语言中很多时候我们都是使用指针传参
C++
    按值传递
    按引用传递,避免复制大量数据的开销,提高性能
    当然C++中肯定也是可以使用指针进行传参的

引用特性

1:引用是别名,在声明时必须初始化,在实际代码中主要用作函数的形式参数
2: 引用作为目标的别名(小名)而使用,对引用的改动实际上是对目标的改动
3:为了建立引用,先写上目标的类型,再加上引用运算符”&”,然后是引用的名字
4:对引用的修改其实就是对原来变量的值的修改
5:引用的地址与引用变量的地址指向的是同一个地址

    如:
        int& a;
    引用是
        const int *p = &a的伪代码(常量指针,指向的地址是常亮,不允许进行改变的)

例子:
    int intOne;
    int& rInt = intOne;
    intOne = 5;
    cout <<"intOne :"<<intOne<<endl;
    cout <<"rInt:  "<<rInt<<endl;
    rInt = 7;
    cout << "intOne :"<<intOne<<endl;
    cout<<"rInt: "<<rInt<<endl;

引用操作:
&只有在声明引用时候是引用操作符,其他时候都是地址操作符号

引用和变量指向同一个存储单元
引用一旦初始化,它就维系在一定的目标上,再也不会分开

    int val = 0;
    int& rVal = val;
    cout <<&(val) <<endl;
    cout <<&(rVal) <<endl;

引用和指针的差别:

1:指针是个变量,可以把它再赋值成别处的地址
2:建立引用时必须进行初始化并且绝对保证不会再关联其他不同的变量
3:由于指针也是变量,所有可以有指针变量的引用
    int *a = NULL;
    int *&rpa = a;
    int b = 8;
    rpa = &b;
4:void引用是不合法的     ------->void &a = 3;
5:不能建立引用的数组
    绝对禁止:int & a[10] = b;
6:没有引用的指针和引用的引用
7:有空指针无空引用

引用的参数传递:

传递引用给函数与传递指针的效果是一样的
使用引用作为参数比使用指针作为参数有更清晰的语法

    void swap(int&x,int&y);

    void swap(int&x,int&y){
        int temp;
        temp = x;
        x = y;
        y = temp;
    }

使用引用作为参数和返回值给函数的意义:

函数只能返回一个值,如果程序需要从函数返回两个数值怎么办
解决这一个问题的办法之一就是引用给函数传递两个参数,然后由往目标中填入争取的数值
函数返回值时,要生成一个值副本,而用引用返回值时候,不生成值的副本,所以提高了效率

int result = 0;         //注意要在返回引用之外;
int& func(int r){ //返回引用
    result = r*r;
    return result;
}

如果返回不在作用域范围内的变量或对象的引用的时候,那么这个时候就是有很大问题的,这是返回一个局部作用域指针的性质是一样的(局部变量在调用完毕之后在栈中内存会被回收掉,这就导致其指向的空间值具有不确定性的数值)
/*
 * ===========================================================================
 *
 *       Filename:  reference.cpp
 *    Description:  
 *        Version:  1.0
 *        Created:  2017年05月23日 23时18分32秒
 *       Revision:  none
 *       Compiler:  gcc
 *         Author:   (), 
 *        Company:  
 *
 * ===========================================================================
 */

#include<iostream>
using namespace::std;

void swap(int &swap_num_1,int& swap_num_2);
int & return_result(int &num);

int main(int argc,char * argv[]){
  int intOne;
  int &intOneReference = intOne;

  intOne = 10;
  cout << intOne << endl;
  cout << intOneReference <<endl;

  //对引用的修改其实就是对引用的变量的修改
  intOneReference = 15;

  cout << intOne << endl;
  cout << intOneReference <<endl;

  cout << "=================="<<endl;
  cout << &intOneReference <<endl;
  cout << &intOne << endl;

  int num1 = 10;
  int num2 = 20;
  swap(num1,num2);

  cout << num1 << endl;
  cout << num2 << endl;

  int a = 10;
  int &num = a;
  num = return_result(num);
  cout <<num <<endl;

  return 0;
}

void swap(int &swap_num_1,int& swap_num_2){
  int num;
  num = swap_num_1;
  swap_num_1 = swap_num_2;
  swap_num_2 = num;
}


int& return_result(int &num){
   num = num * num;
   return num;
}

内联函数

内联函数

函数:
函数能够从输入数据或参数获得信息

    输入数据流----->函数---->返回值

函数调用需要建立栈内存环境,进行参数传递,并产生程序的执行转移,这些工作都需要一些时间开销。有些函数使用频率高,但代码却很短;

C++提供了inline函数,减少函数调用的成本
编译器看到inline后,为该函数 创建一段代码,以便在后面每次碰到该函数的调用都用一段代码来代替
内联函数的声明:
内联函数必须在调用之前声明或定义;
例子:


        inline boolean isnumber(char);
        char c;
        while((c=cin.get())!='\n'){
            if(isnumber(c))
                cout<<"you enter a digit \n";
            else
                cout<<"you enter a non-digit \n";
        }

        inline booelan isnumber(char c){            
                return (c>='0'&&c<='9')?true:false;
        }

内联函数的函数体限制
1:内联函数中,不能有复杂的结构控制语句,如switch和while。如果内联函数有这些语句,编译器则视其为普通函数
2:递归函数不能做内联函数
3:将大多数inline函数限制在小型,被频繁调用的函数上
4:内联函数只适合于只有1到5行的小函数,对于比较长的函数,函数调用和返回的开销相对来说都微不足道,所有也没有必要用内联动函数

内联函数和宏定义:

宏定义可以代替小函数定义,但是有缺陷
宏只是告诉编译器简单的替代代码。不检查参数类型
往往造成语句的实际结果不能代表程序员的意图

通过一个内联函数可以得到所有宏的替换功能和所有可遇见的状态及常规函数的就类型检查
inline int Max(int a,int b)【
    return a>b?a:b
}

默认参数的函数

默认参数的函数:

    默认参数的函数

    给一个函数默认参数的值
    调用函数的时候可以不指定全部的参数
    为可以不指定的参数提供默认值:
        int add(int x = 5,int y = 6,int z = 3);
        int main(){
            add();  //所有这三个参数都采用默认值
            add(1,5);   //第三个参数采用默认值
            add(1,2,3); //不采用默认值
        }

默认参数的顺序规定:
    如果一个函数中的有多个默认参数,则形参分布中,默认参数应从右往左逐渐定义,当调用函数时候,只能向左匹配参数,例如:
    void func(int a = 1,int b,int c = 3,int d = 4); //error
    void func(int a,int b = 2,int c = 3,int d = 4);//ok
    对于第二个函数声明,其调用的方法规定为:
        func(10,15,20,30);//调用的时候给出实际的参数
        func();//error
        func(12,12);参数c,d默认
        func(2,15,,20);//只能从右往左便开始匹配

如果是有默认参数的情况下,内部的参数是可以不用写那么全的

如   foo(int a = 30,int b = 40,int c = 50);
那么此时调用的时候可以
foo(30);
foo(30,40);
foo(30,40,50);

函数重载

函数重载:

函数重载:
定义:两个或者两个以上的函数,取相同的函数名字,但是形参数的个数或者类型不同,编译器根据实参和形参数的类型及个数的最佳匹配,自动确定调用哪一个函数,这就是函数的重载;
重载的重要性:

        在C语言中每个函数都必须要有唯一的名字
        int abs(int);
        long labs(long);
        double dabs(double);
        这每个函数所做的事情都是一样的,相对比较冗余;
    C++中:
        int abs(int);
        long abs(long);
        double  abs(double); 
        C++用一种命名技术可以准确判断使用哪一个函数;

函数重载的顺序:
寻找一个严格的匹配,如果找到了那就用哪一个函数
通过内部转换寻求一个匹配,只要找到了,就用那个函数
通过用户定义的转换寻求一个匹配,若能查出有唯一的一组转换,就用那个函数

FILE
LINE
func

默认参数和函数重载:

    默认参数可将一系列简单的重载函数合成一个
    void point(int ,int){

    }

    void point(int a){
        return point(a,4);
    }

    void point(){
        return point(3,4);
    }
    可以用默认参数的函数来替代:
        void point(int=3,int=4);

如果一组重载函数都允许相同实参个数的调用,将会引起调用的二异性:

在C语言头文件中的extern “C”

常见的C语言头文件格式:
    #ifndef __FUNC__
    #define __FUNC__

    #ifdef __cplusplus
        extern "C"{
    #endif

        void func();
        int foo(int a,int b);
    #ifdef __cplusplus
    }
    #endif
    #endif

函数模板:

函数模板(template):

泛型编程:独立于任何特定类型的方式编码
模板是泛型编程的基础
模板使程序员能够快速建立具有类安全的类库集合和函数集合
它的实现方便了大规模的软件开发
现有的框架Framework大都使用模板
类模板和函数模板
STL是标准的模板库

函数模板的定义:
    template<类型形式参数表> 返回类型 FunctionName(形式参数表)
        //函数定义体
    }

例子:求绝对值的模板:
    #include<iostream>
    using namespace::std;

    template <typename T>
    T abs(T x){
        return x<0 ? -x : x;
    }
    int main(){
        int n  = 5;
        double d = -5.5;
        cout <<abs(n)<<endl;
        cout <<abd(d)<<endl;
        return 0 ;
    }

对于具有各种参数类型,相同个数,相同顺序,的同一函数,如果用宏定义来写:

#define max(a,b) ((a)>(b)?a:b)

template <class T>
T max(T a,T b){
    return a>b ?a :b;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在国际象棋中,学会如何移动棋子只能算是入门:要想掌控整个棋局,我们必须了解自己所下的每一步棋后的策略和战术。在C++中也同样如此。掌握正确的策略可以帮助我们避免常见的陷阱,并提高我们的工作效率。在本书中,C++专家Rob Murray就与我们分享了他宝贵的经验和建议,以帮助初中级C++程序员得到进一步的提高。  在本书中,作者大量采用了实际开发中的代码来作为示例,向读者展示了那些有用的编程策略,并对那些有害的做法进行了警示。为了帮助读者更好地理解,在书中的每一章结束前,在该章中被介绍过的主要内容都被放到了一个列表中,此外,书中还给出了一些问题来激励读者们进行更多的思考和讨论。 本书在一开始就向我们讲解了如何为我们的设计选择正确的抽象,提示我们注意抽象和现实之间的区别。然后,我们就将学到如何将已得到的抽象转化成一个(或多个)C++中的类,期间进行的讨论所涵盖的范围上至高层的设计策略,下至底层的接口和实现细节。   接下来本书对单继承和多重继承进行了深入的探索。一开始书中会给出一个关于它们应该用在设计的什么地方的讨论,然后就是一些详细的示例代码,用来向我们演示如何在实践中使用这些概念。对于“如何构建可派生出其他类的类”以及“这么做的好处何在”,书中还专门抽出了一章来讨论它们。   对于C++中新增的模板特性,通过从基础开始到逐步地接触实际应用中的示例,Rob Murray向我们展示了其空前的洞察力。作者同时也向我们展示了多种特定的技巧,以使我们的程序更快、重用性更高,并且更健壮。异常是C++中另外一个新增的特性,对于何时该使用它,何时不该使用它,Murray也向我们给出了他的建议。在本书的最后,我们还可以学到如何将一个项目从C移植到C++之上,书中对该过程的讨论不但包括了其中可能出现的技术问题,也包括了使用技术的“人”的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值