博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PoEdu - C++阶段班【Po学校】- 第3天
阅读量:5882 次
发布时间:2019-06-19

本文共 5350 字,大约阅读时间需要 17 分钟。

引用

 C中指针的功能强大,使用起来繁杂,因为指针要控制的东西太多:有指针的类型,指针的解引用,指针空间内的值,它本身是有空间的,有自己的地址等。指针也是强大的,比如:我们要在函数之内,修改方法之外的值的话,必需用到指针。但这里指针的使用,使得我们要修改的类型,变成了另外一种类型(如:int*)由原来的类型变成了指针类型。

 引用  &  能实现指针一模一样的功能,但它不改变数据的状态(类型)。

 用法:int val = 100;  int &refval = val ;

指针我们可以直接指向一个NULL,但引用必需要指向一个变量。这是与指针不一样的地方。引用是变量的别名。

1 引用是没能独立空间的,所以它一定要与一个变量绑定,才能共用一段空间。

2 引用确定后,它无法被更改。一旦经理室了一个对象,就无法再次赋值为别的对象。

 

上图所有针对refval的操作,都作用在绑定的变量val上。

3 引用,它与引用 的变量共用同一段空间

示例:

#include 
using namespace std;void Swap(int &rhs, int &lhs){ int tmp = rhs; rhs = lhs; lhs = tmp;}int main(){ int val = 100; int &refval = val ; int num = 50; //refval = num; //这里示范,相当于这样:val = num Swap(val,num); cout << val << " " << num ; return 0;}

运行:  50      100

数据交换成功。 

 

 

引用它是安全的,可以理解为阉割版的指针:

 

#include  
void Swap(int &rhs,int &lhs){ int tmp = rhs; rhs = lhs; lhs = tmp;}int main(){ int val = 100; int &refval = val; //引用是变量的别名,更多是在语法层面的。 //它是没有独立空间的; //引用确定后,它的值是不能更改的。 // 共用同一空间 int *pVal = &val; val = 50; std::cout << val; //50 std::cout << refval; //50 std::cout << pVal; //val地址 std::cout << *pVal; //50 //Swap(val, num); return 0;}

断点 运行:

 

再看:

运行:

 

 再再看:

运行如下:

 

 

 引用的意义在于:代码的可读性更强,并且安全,但凡一引用,永远无法更改。

 

 提问:这两种写法正确吗?  1  // int &refval = 100;   2  //int *pval = &100;

 

这样子是不行的:  看1的代码,一个引用int &refval等于一个立即数100,立即数100是没有内存地址的,也就是没有空间的,虽然说引用没有独立的空间,但它指向一个变量后,也就是要有空间的,共享空间而已。这里立即数不在内存里面产生,在内存中没有空间,所以1的写法是错误的。

  看2的代码,左边是一个int * 的指针pval,等号后面,把100这个立即数的地址,赋值给左边的指针?~!立即数在寄存器里面产生,不在内存中存在。很显然,示例2的代码也是错误的。

 

 

 


复习C语言中 const 的用法

 1  示例  代码:const int *pVal = &val;   请问:这段代码const修饰了什么?是什么不能修改?是地址pval,还是解引用的值不能修改?用编译器的贪心法则来套用:const先看左边,左边为空,那转向右边,第一个int ,再看第二个*,可以修饰,再看pVal,最后遇到赋值等号,那么const有效的修饰3个连接:int *pVal,得出结论:*pVal解引用的值被const修饰,值不能修改。

2 示例  代码:int const *pVal = &val;  这段代码又是什么不能修改?  当const在*号的左边时,和代码1一样。

3 示例 代码:  int * const pVal = &val;  当const在*号的右边时:(看口诀:左数右指。)那么就是这根“指针”本身不能被改变。就是指针里面的内存地址(俗称一根指针)。

 

 在C++中const 和&引用一块使用会产生什么化学反映呢?

示例  //const int &refval = val;   这里是什么无法修改呢?  A  值   B  地址

答案是:以上都不正确,因为const的引用,要指向const修饰的类型

如:const int num = 500; const int & refnum = num;  这样出现才是正确的。如果你要引用一个常量的话,前面一定要加上const修饰。


  

 

 

 

 

 

 

 

   运行,交换成功!

函数void Swap(int &rhs, int &lhs);  相当于传递了指针地址,也就是说传递了引用 的共享空间,在C中我们用指针,C++中我们用引用。可以这么认为:它将函数形参实参化了。引用相当于直接传递了本身(地址)。好处就是:函数内将参数作为变量使用,作用于外部。

函数之间的值传递是通过栈来完成的,如果我要传递的是一个比较大的结构体,那么这里就可以使用“&引用”,传递地址以节省空间。

实际上我们想传递引用时,常见的情况下,只需要传递地址,数据并不想被修改,那么,引用要加上const 来修饰,以避免被修改的风险。而且下面调用函数时,并不用写上const对应参数,因为它会自动做一个提升。

 

引用还可以作为函数的返回

   

  引用作为返回值的写法

 

 

 

看代码 1 

#include  
int array[] = { 18,21,32,48,1001 };int &Index(int index){ return array[index];}int main(){ Index(0) = 100; return 0;}

代码 2

#include  
int array[] = { 18,21,32,48,1001 };int &Index(int index){ return array[index];}int *Index(){ retrun &array[2];}int main(){ Index(0) = 100; *Index() = 300;return 0;}

以上是返回引用与返回指针的写法。

 这里打印指针和引用,直观的认识指针和引用之间的区别:

#include  
int array[] = { 18,21,32,48,1001 };int &Index(int index){ return array[index];}int *Index(){ return &array[2];}int main(){ Index(0) = 100; *Index() = 300; std::cout << array[0] << " " << Index(); //100 //地址 int num = 0; int &ref = num, *p = # std::cout << ref << p << *p; //0 //地址//0 return 0;}

  

引用能不能取代指针呢?答:不能,因为引用不能指向推空间。 

C++很强大:请看这行代码   int *&refp = p;

 

 

  

 C++11中间的auto  自动推导所需类型

这里有行永远也不要写的代码:*p = num;  auto &refp = p;   永远不要拿一个指针去做它的引用。

 

 

 


 

 

 

 
类与对象
 

 

 

类:比如人类,虚的,抽象的,出现在人们口中,出现在纸上,是一个概念性的,属性的集合。 

 

 
 对象:实体的,活生生的,能动能说能笑,吃喝拉撒……
 

 

 

 

 
 

 

 

 

C++中的类:公有  public :   私有   private :   默认私有。

 

私有属性只能类内部访问。

 

 

 

 

其实还有一种  protected  :    受保护的。

 

 

 

 构造函数与析构函数

 

 

 代码:

#include 
class MyString{ char *str; int len;public: MyString() //构造函数 { std::cout << "MyString()被调用" << std::endl; } ~MyString() //析构函数 { std::cout << "~MyString()被调用" << std::endl; } int &Len() { return len; }};int main(){ MyString demo; demo.Len() = 100; return 0;}

断点运行:

 

 

构造函数与类名相同,没有返回值

你不写,编译器默认生成

 

 

当对象产生时,构造函数被调用。

 
 

 

析构函数    当对象销毁时,析构函数被调用

 

 

 

 

当你创建了构造函数,编译器不会再自动生成构造函数。

析构函数里面,写入释放内存的代码,是常见的手法。

 

 

 我们无法直接:类.方法  因为类是虚的,是图纸,是设计方案,是汽车图纸,只有实体小车,才有车门,有方向盘,所以老司机要开车,首先要有个对象:一辆车。在计算机的世界里面,类不占内存,对象才占用内存。占用内存的,才是实体对象。

对象是实体的,就如一块实体的手表,手表设计图纸就是类,工厂按设计图纸加工,材料是各属性变量等,默认构造成一个什么样子,就有了构造函数,不合格就的产品要收回,就有了析构函数。所以每个手表(对象)就有初始的大致的模样和功能(构造函数 ),还有回收方法(析构函数),有些是在表面可见的,可以控制的(public权限),而有些是封闭在手表内部,是不可见的(private权限);

 

 

现得知一个类:构造函数带有参数,如果想创建不带任何参数的对象,两种方法:1  构造函数重载,加一个没有任何参数的构造函数;2  在现有的参数里面写入默认实参。

 

 

类  内部变量书写规范  加下划线

 

 

 

作业:

 

 附上代码,以及一个小发现:

#define _CRT_SECURE_NO_WARNINGS#include 
#include
class MyString{ char *_str; int _len;public: MyString() { _str = new char[100]; _len = 100; } MyString(char *str) { _len = strlen(str); _str = new char[_len+ sizeof(char)]; strcpy(_str, str); } ~MyString() //析构函数 { delete[]_str; } char *GetString() { return _str; }};int main(){ MyString demo1; MyString demo2(); //前者是新建一个以demo1命名的对象,后者是声明一个返回MyString类型的函数demo2(). MyString demo("I Love Mark"); std::cout << demo.GetString(); return 0;}

 检验一下上面高亮的demo2,看它到底是对象,还是方法。

验证说明:demo2是方法,不是对象。

 

 

转载于:https://www.cnblogs.com/bing-z/p/6213357.html

你可能感兴趣的文章
spring xml properties split with comma for list
查看>>
判断点是否在三角形内
查看>>
Android实战简易教程-第二十三枪(基于Baas的用户注冊验证username是否反复功能!)...
查看>>
在odl中怎样实现rpc
查看>>
leetcode 110 Balanced Binary Tree
查看>>
python活用isdigit方法显示系统进程
查看>>
项目开发总结
查看>>
知行合一
查看>>
jmeter插件之jsonpath提取响应结果和做断言
查看>>
发布支持多线程的PowerShell模块 —— MultiThreadTaskRunner
查看>>
Ubuntu ctrl+alt会导致窗口还原的问题
查看>>
第四十期百度技术沙龙笔记整理
查看>>
推荐系统那点事 —— 基于Spark MLlib的特征选择
查看>>
linux 下RTL8723/RTL8188调试记录(命令行)【转】
查看>>
SpringMVC案例1——对User表进行CRUD操作
查看>>
[Contiki系列论文之1]Contiki——为微传感器网络而生的轻量级的、灵活的操作系统...
查看>>
Android 网络编程 记录
查看>>
微软同步发行Windows 10和Windows 10 Mobile系统更新
查看>>
Zeppelin的入门使用系列之使用Zeppelin运行shell命令(二)
查看>>
form表单下的button按钮会自动提交表单的问题
查看>>