当前位置:首页技术教程第三章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人
第三章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人
°
  • 素材类型: 原创-素材
  • 上传时间:

接第二章C++编程宝典

2.5. 默认参数(default parameters)
通常情况下,函数在调用时,形参从实参那里取得值。对于多次调用用一函数同一实参时,C++给出了更简单的处理办法。给形参以默认值,这样就不用从实参那里取值了。
2.5.1. 示例
单个参数

#include  
#include 
using namespace std;
void weatherForcast(char * w="sunny")
{
    time_t t = time(0);
    char tmp[64];
    strftime( tmp, sizeof(tmp), "%Y/%m/%d %X %A ",localtime(&t) );
    cout<<tmp<< "today is weahter "<<w<<endl;
}
int main()
{
    //sunny windy cloudy foggy rainy
    weatherForcast();
    weatherForcast("rainny");
    weatherForcast();
    return 0;
}

多个参数

float volume(float length, float weight = 4,float high = 5)
{
     return length*weight*high;
}
int main()
{
     float v = volume(10);
     float v1 = volume(10,20);
     float v2 = volume(10,20,30);
     cout<<v<<endl;
     cout<<v1<<endl;
     cout<<v2<<endl;
     return 0;
}

2.5.2. 规则
1,默认的顺序,是从右向左,不能跳跃。
2,定义在前,调用在后(此时定义和声明为一体),默认认参数在定义处。声明在前,调用在后,默认参数在声明处。
3,一个函数,不能既作重载,又作默认参数的函数。当你少写一个参数时,系统 无法确认是重载还是默认参数。

void print(int a)
{
}
void print(int a,int b =10)
{

}
int main()
{
     print(10);
     return 0;
}
main.cpp:16: error: call of overloaded 'print(int)' is ambiguous
print(10);

2.6. 引用(Reference)
2.6.1. 引用的概念
变量名,本身是一段内存的引用,即别名(alias)。此处引入的引用,是为己有变量起一个别名。
声明如下

int main()
{
    int a;
    int &b = a;
}

2.6.2. 规则
1,引用没有定义,是一种关系型声明。声明它和原有某一变量(实体)的关系。故而类型与原类型保持一致,且不分配内存。与被引用的变量有相同的地址。
2,声明的时候必须初始化,一经声明,不可变更。
3,可对引用,再次引用。多次引用的结果,是某一变量具有多个别名。
4,&符号前有数据类型时,是引用。其它皆为取地址。

int main()
{
    int a,b;
    int &r = a;
    int &r = b; //错误,不可更改原有的引用关系
    float &rr = b; //错误,引用类型不匹配
    cout<<&a<<&r<<endl; //变量与引用具有相同的地址。
    int &ra = r; //可对引用更次引用,表示 a 变量有两个别名,分别是 r 和 ra
}

2.6.3. 应用
C++很少使用独立变量的引用,如果使用某一个变量,就直接使用它的原名,没有必要使用他的别名。
作函数参数引用 (call by value)

void swap(int a, int b); //无法实现两数据的交换
void swap(int *p, int *q); //开辟了两个指针空间实现交换

作函数参数引用 (call by reference)

void swap(int &a, int &b){
    int tmp;
    tmp = a;
    a = b;
    b = tmp;
}
int main(){
    int a = 3,b = 5;
    cout<<"a = "<<a<<"b = "<<b<<endl;
    swap(a,b);
    cout<<"a = "<<a<<"b = "<<b<<endl;
    return 0;
}

c++中引入引用后,可以用引用解决的问题。避免用指针来解决
2.6.4. 引用提高
引用的本质是指针,C++对裸露的内存地址(指针)作了一次包装。又取得的指针的优良
特性。所以再对引用取地址,建立引用的指针没有意义。
1,可以定义指针的引用,但不能定义引用的引用。

int a;
int* p = &a;
int*& rp = p; // ok
int& r = a;
int&& rr =

案例:

#include 
using namespace std;
void swap(char *pa,char *pb)
{
    char *t;
    t = pa;
    pa = pb;
    pb = t;
}
void swap2(char **pa,char **pb)
{
    char *t;
    t = *pa;
    *pa = *pb;
    *pb = t;
}
void swap3(char * &pa,char *&pb)
{
    char *t;
    t = pa;
    pa = pb;
    pb = t;
}
int main()
{
    char *pa = "china";
    char *pb = "america";
    cout<<"pa "<<pa<<endl;
    cout<<"pb "<<pb<<endl;
// swap(pa,pb);
// swap2(&pa,&pb);
    swap3(pa,pb);
    cout<<"pa "<<pa<<endl;
    cout<<"pb "<<pb<<endl;
    return 0;
}

2,可以定义指针的指针(二级指针),但不能定义引用的指针。

int a;
int* p = &a;
int** pp = &p; // ok
int& r = a;
int&* pr = &r; // error

3,可以定义指针数组,但不能定义引用数组,可以定义数组引用。

int a, b, c;
int* parr[] = {&a, &b, &c}; // ok
int& rarr[] = {a, b, c}; // error
int arr[] = {1, 2, 3};
int (&rarr)[3] = arr; // ok 的

4,常引用
const 引用有较多使用。它可以防止对象的值被随意修改。因而具有一些特性。
(1)const 对象的引用必须是 const 的,将普通引用绑定到 const 对象是不合法的。这个原因比较简单。既然对象是 const 的,表示不能被修改,引用当然也不能修改,必须使用 const 引用。实际上,const int a=1; int &b=a;这种写法是不合法的,编译不过。
(2)const 引用可使用相关类型的对象(常量,非同类型的变量或表达式)初始化。
这个是 const 引用与普通引用最大的区别。const int &a=2;是合法的。double x=3.14; constint &b=a;也是合法的。
常引用原理:
const 引用的目的是,禁止通过修改引用值来改变被引用的对象。const 引用的初始化特性较为微妙,可通过如下代码说明

double val = 3.14;
const int &ref = val;
double & ref2 = val;
cout<<ref<<" "<<ref2<<endl;
val = 4.14;
cout<<ref<<" "<<ref2<

上述输出结果为 3 3.14 和 3 4.14。因为 ref 是 const 的,在初始化的过程中已经给定值,不允许修改。而被引用的对象是 val,是非 const 的,所以 val 的修改并未影响ref 的值,而 ref2 的值发生了相应的改变。
那么,为什么非 const 的引用不能使用相关类型初始化呢?实际上,const 引用使用相关类型对象初始化时发生了如下过程:

int temp = val;
const int &ref = temp;

如果 ref 不是 const 的,那么改变 ref 值,修改的是 temp,而不是 val。期望对 ref的赋值会修改 val 的程序员会发现 val 实际并未修改。

int i=5;
const int & ref = i+5;
//此时产生了与表达式等值的无名的临时变量,
//此时的引用是对无名的临时变量的引用。故不能更改。
cout<<ref<<endl;

2.6.5. 引用的本质浅析
2.6.5.1. 大小与不可再引用
引用的本质是指针,是个什么样指针呢?可以通过两方面来探究,初始化方式和大小

struct TypeP
{
    char *p;
};
    struct TypeC
{
    char c;
};
    struct TypeR
{
    char& r; //把引用单列出来,不与具体的对像发生关系
};
int main()
{
// int a;
// int &ra = &a;
// const int rb; //const 类型必须要初始化。
printf("%d %d %dn",sizeof(TypeP),sizeof(TypeC),sizeof(TypeR));
   return 0;
}

结论:
引用的本质是,是对常指针 type * const p 的再次包装。char &rc == *pc double &rd == *p
2.6.5.2. 反汇编对比指针和引用
原程序

#include 
using namespace std;
void Swap(int *p, int *q)
{
    int t = *p
    *p = *q;
    *q = t;
}
void Swap(int &p, int &q)
{
    int t = p;
    p = q;
    q = t;
}
int main()
{
    int a = 3; int b =5;
    Swap(a,b);
    Swap(&a,&b);
    return 0;
}

汇编程序:

[1] {
55 push %ebp
<+0x0001> 89 e5 mov %esp,%ebp
<+0x0003> 83 e4 f0 and $0xfffffff0,%esp
<+0x0006> 83 ec 20 sub $0x20,%esp
<+0x0009> e8 ce 0a 00 00 call 0x402130 <__main>
[1] int a = 3; int b =5;
<+0x000e> c7 44 24 1c 03 00 00 00 movl $0x3,0x1c(%esp)
<+0x0016> c7 44 24 18 05 00 00 00 movl $0x5,0x18(%esp)
[1] Swap(a,b);
<+0x001e> 8d 44 24 18 lea 0x18(%esp),%eax
<+0x0022> 89 44 24 04 mov %eax,0x4(%esp)
<+0x0026> 8d 44 24 1c lea 0x1c(%esp),%eax
<+0x002a> 89 04 24 mov %eax,(%esp)
<+0x002d> e8 ac ff ff ff call 0x401632 <Swap(int&, int&)>
[1] Swap(&a,&b);
<+0x0032> 8d 44 24 18 lea 0x18(%esp),%eax
<+0x0036> 89 44 24 04 mov %eax,0x4(%esp)
<+0x003a> 8d 44 24 1c lea 0x1c(%esp),%eax
<+0x003e> 89 04 24 mov %eax,(%esp)
<+0x0041> e8 76 ff ff ff call 0x401610 <Swap(int*, int*)>
[1] return 0;
<+0x0046> b8 00 00 00 00 mov $0x0,%eax
[1] }
<+0x004b> c9 leave
<+0x004c> c3 ret

0x401632 <Swap(int&,int&)>

      12 [1]{
0x401632 55 push %ebp
0x401633 <+0x0001> 89 e5 mov %esp,%ebp
0x401635 <+0x0003> 83 ec 10 sub $0x10,%esp
      13 [1] int t = p;
0x401638 <+0x0006> 8b 45 08 mov 0x8(%ebp),%eax
0x40163b <+0x0009> 8b 00 mov (%eax),%eax
0x40163d <+0x000b> 89 45 fc mov %eax,-0x4(%ebp)
      14 [1] p = q;
0x401640 <+0x000e> 8b 45 0c mov 0xc(%ebp),%eax
0x401643 <+0x0011> 8b 10 mov (%eax),%edx
0x401645 <+0x0013> 8b 45 08 mov 0x8(%ebp),%eax
0x401648 <+0x0016> 89 10 mov %edx,(%eax)
      15 [1] q = t;
0x40164a <+0x0018> 8b 45 0c mov 0xc(%ebp),%eax
0x40164d <+0x001b> 8b 55 fc mov -0x4(%ebp),%edx
0x401650 <+0x001e> 89 10 mov %edx,(%eax)
      16 [1] }
0x401652 <+0x0020> c9 leave
0x401653 <+0x0021> c3 ret

0x401610 <Swap(int*,int*)>

       6 [1] {
0x401610 55 push %ebp
0x401611 <+0x0001> 89 e5 mov %esp,%ebp
0x401613 <+0x0003> 83 ec 10 sub $0x10,%esp
       7 [1] int t = *p;
0x401616 <+0x0006> 8b 45 08 mov 0x8(%ebp),%eax
0x401619 <+0x0009> 8b 00 mov (%eax),%eax
0x40161b <+0x000b> 89 45 fc mov %eax,-0x4(%ebp)
       8 [1] *p = *q;
0x40161e <+0x000e> 8b 45 0c mov 0xc(%ebp),%eax
0x401621 <+0x0011> 8b 10 mov (%eax),%edx
0x401623 <+0x0013> 8b 45 08 mov 0x8(%ebp),%eax
0x401626 <+0x0016> 89 10 mov %edx,(%eax)
       9 [1] *q = t;
0x401628 <+0x0018> 8b 45 0c mov 0xc(%ebp),%eax
0x40162b <+0x001b> 8b 55 fc mov -0x4(%ebp),%edx
0x40162e <+0x001e> 89 10 mov %edx,(%eax)
       10 [1] }
0x401630 <+0x0020> c9 leave
0x401631 <+0x0021> c3 ret

对比结果
第三章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人
2.7. new/delete
c 语言中提供了 malloc 和 free 两个系统函数,完成对堆内存的申请和释放。而 c++则提供了两关键字 new 和 delete ;
2.7.1. new用法:
1.开辟单变量地址空间

int *p = new int; //开辟大小为 sizeof(int)空间
int *a = new int(5); //开辟大小为 sizeof(int)空间,并初始化为 

2.开辟数组空间

一维: int *a = new int[100];开辟一个大小为 100 的整型数组空间
二维: int (*a)[6] = new int[5][6]
三维: int (*a)[5][6] = new int[3][5][6]
四维维及其以上:依此类推

2.7.2. delete用法:
1. int *a = new int;

delete a; //释放单个 int 的空间

2.int *a = new int[5]

delete []a; //释放 int

2.7.3. 综合用法

#include 
#include 
#include 
#include 
using namespace std;
int main()
{
    int *p = new int(5);
    cout<<*p<<endl;
    delete p;
    char *pp = new char[10];
    strcpy(pp,"china");
    cout<<pp<<endl;
    delete []pp;
    string *ps = new string("china");
    cout<<*ps<<endl; //cout<<ps<<endl;
    delete ps;
    char **pa= new char*[5];
    memset(pa,0,sizeof(char*[5]));
    pa[0] = "china";
    pa[1] = "america";
    char **pt = pa;
    while(*pt)
    {
        cout<<*pt++<<endl;
    }
    delete []pt;
    int (*q)[3] = new int[2][3];
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<3; j++)
        {
            q[i][j] = i+j;
        }
    }
    for(int i=0; i<2; i++)
    {
    for(int j=0; j<3; j++)
    {
        cout<<q[i][j];
    }
    cout<<endl;
   }
   delete []q;
   int (*qq)[3][4] = new int [2][3][4];
   delete []qq;
}

2.7.4. 关于返回值

int main()
{
    //c 语言版本
    char *ps = (char*)malloc(100);
    if(ps == NULL)
       return -1;
    //C++ 内存申请失败会抛出异常
    try{
        int *p = new int[10];
    }catch(const std::bad_alloc e) {
        return -1;
    }
    //C++ 内存申请失败不抛出异常版本
    int *q = new (std::nothrow)int[10];
    if(q == NULL)
        return -1;
    return 0;
}

2.7.5. 注意事项
1,new/delete 是关键字,效率高于 malloc 和 free.
2,配对使用,避免内存泄漏和多重释放。
2,避免,交叉使用。比如 malloc 申请的空间去 delete,new 出的空间被 free;
2.7.6. 更进一步
如果只是上两步的功能,c 中的 malloc 和 free 完全可以胜任,C++就没有必要更进一
步,引入这两个关键字。
此两关键字,重点用在类对像的申请与释放。申请的时候会调用构造器完成初始化,
释放的时候,会调用析构器完成内存的清理。以后我们会重点讲

温馨提示:

文章标题:第三章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

文章链接:https://www.xiciw.com/jsjc/945.html

更新时间:2024年01月29日

本站大部分内容均收集于网络!若内容若侵犯到您的权益,请发送邮件至:xiciw#qq.com我们将第一时间处理!

资源所需价格并非资源售卖价格,是收集、整理、编辑详情以及本站运营的适当补贴,并且本站不提供任何免费技术支持。

                               

所有资源仅限于参考和学习,版权归原作者所有,更多请阅读菜鸟资源服务协议

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

给TA打赏
共{{data.count}}人
人已打赏
技术教程

第二章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

2024-1-27 21:06:00

技术教程

第四章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

2024-1-28 19:02:00

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索