<文章原创,转载请说明出处,联系信箱623730587@qq.com>
一、开题
1 如果你一个人站在马路旁边看人来人往,突然有一个女孩子跑过来对你说”哇,这么冷得天,那个人穿短裤,好
搞笑啊!“,这意味着什么?
2 昨天理了个帅气的发型,去街上逛,于是就发生了上面一幕(得意一下),我想了老半天问“你是不是想泡我?”
结果...
3 好了,结果留给大家去想象,开始今天的内容。
二、c++中结构体或者类的大小(小小小知识点)
1 有如下结构体
struct Date
{
int year;
int month;
int day;
void show()
{
cout << year << '-' << month << '-' << day << endl;
}
}
2 这个结构体的大小为12个字节,毫无疑问,但是我要提出一个问题,结构体的show()函数难道不占用空间大小
吗?
3 好吧,我不卖关子了,这是因为,变量是存放在栈或者堆里面的,而函数是存放在代码区里面的,表面上看,
它们存放在同一个结构体中,但是本质上和c语言的结构体没什么区别,函数存放在代码区,变量存放在堆或
栈里面,只是c++的设计者将它们的身体放在了一起而已,身在曹营心在汉啊!这就是传说中的、大名鼎鼎的
封装,没有那么邪乎吧!
4 现在大家明白了为什么上面的结构体大小为12了吧。
三、char数组地址的输出(小小小知识点)
1 有如下的两个数组,其中第二个数组是存放在和data一样的栈空间中,而且地址相同,这是新的语法规定哦,
表示将堆内存分配到栈内存中去,由于栈是自动回收的,这样就不用自己delete了,这个好吧?
char data[100];
int * pch = new (data)int[25];
2 现在我们要输出data的地址
cout << data << endl;
3 上面的输出语句是一句乱码,为什么呢?数组名不是代表首地址吗?这是因为编译器会将char数组和char*理解
为字符出串,哦,终于明白了,原来上面的输出语句输出的是一个字符串啊,没有赋值当然是乱码,那怎么办?
cout << &data << endl;
这样就行了。如果是int类型数组的话,编译器就不可能认为是字符串了。
四、引用
1 引用就是变量的别名。就像我大名叫卓别林,小名叫狗蛋,其实是一个人。
2 用法:
1) 有如下变量
int a = 100;
上述语句执行意味着,操作系统要在内存中分配4个字节的区域,并给这块区域起名为a;一个区域有多个
名字是很正常的需求,所以就出现了引用的概念,到后面大家就会知道引用有大用了哦。
2) 引用的定义
int& pa = a;
这就表示给变量a取了一个别名pa。需要注意的是,定义引用的时候必须给引用赋值,下面语句不行。
int& pa; // error
3) 引用一旦初始化,那么被绑定的变量就服务终身。
int& pa = a;
int& pa = b; // error
ra = b; //right,这一句代码仅仅是将变量b的值赋值给ra。
4)绝对不能返回局部变量的引用,因为一旦函数调用结束,局部变量本身就消失了,所以引用就是无效的。
可以返回全局变量的应用,静态变量的应用,堆内存变量的引用,和引用类型的引用。
3 应用:
1) 函数的传参
我们都知道,如果以值方式传参,那么传递的将是实参的一个副本,也就是将变量复制了一份传给函数。
假如我们要交换两个变量的值:
void swap(int x,int y); // 值传递,要进行变量的复制,如果类型为struct类型,那么就会造成大规模
的复制,另外变量的值不会发生交换
void swap(int* x,int* y); // 指针的方式传递,变量的值发生交换,变量不会发生复制,但地址要复制,
不管传递的是基本类型还是复合类型,都只复制4个字节的地址值。
void swap(int& x,int& y); // 如果以引用的方式传参,那么传递进函数的将会是变量本身,变量不复制
2)函数的返回值
c语言中,函数的返回值一般作为右值,函数返回值一般是只读的,如果想让函数的返回值做左值,那么
就得用指针或者引用。
4 常引用
int& ra = 100; // error,因为引用只能和变量绑定,而不能和常量绑定。
const int& ra = 100; // right
c语言中,函数传递参数是加const的作用是,防止变量的值被修改
void fun(const int x); // 防止值被修改
而c++中,函数传递参数时,加const的作用有两个,防止变量的值被修改,和增强函数的兼容性。
void fun(const int& x); //这样就既可以传递变量,也可以传递常量,增强了兼容性,也防止值被修改
5 引用的底层实现
1)const int* pa; / int const * pa;
上述语句代表的是不能通过指针pa修改内存中的值。但是可以改变指针所指向的地址,这是c语言中的基
本的知识点。
int a = 20;
const int *pa = &a;
*pa = 30; // error,不能通过pa修改它所指向的内存中的值
int b = 40;
pa = &b; // right,指针本身的地址可以改变
int *const pra = &a; // 注意,const的位置在*之后,和上面的语句对比就可以发现不同。这表明不能修改
指针的指向,也就是说pra指针和a的地址绑定,但是可以通过pra修改它所指向的内存中的值。
2)引用则是变量的值可以改变,而变量的地址不可以改变(终生绑定的特性)。说到这里有没有发现,原来
引用的作用和const int* pa的作用是刚好相反的。其实引用本质就是上面的第二种写法int *const pra的定
义。
6 注意引用本身不占用内存大小。
7 思考,引用和指针的联系和区别???
六、c++中的类型转换(四个转换运算符)
1 首先说明c语言中的强制类型转换依然有效,但是c++中尽可能的避免这种强制类型转换。
a static_cast<要转换成的类型> (变量) //在某一个方向上可以做隐式类型转换,那么在相反的转换方向上就可
以使用static_cast
int *pi = new int(100);
void *pv = pi; // 这个方向上,int* 可以隐式转换成void*
int *pt = pv; // 报错,这个时候在另外一个方向上可以做static_cast<> ()的转换。
b dynamic_cast<类型>(变量) //用在具有多态性的父子类之间。(暂时不讲)
c const_cast<类型>(变量) //专业的去常属性的
const int a = 100;
现在我我要改变a的值。
a = 200; // 显然行不通
int *pa = &a; // 错误,a的地址具有常属性
int *pa = (int*)&pa; // 强制转换,可以
*pa = 200;
cout << *pa << endl; // 值是200
cout << a << endl; // 值是100,这里很奇怪,因为c++编译器有优化技术,只要见到const类型的变量,会
像c语言中的宏一样进行快速替换,从而提高效率,但是上面的那种转换让人很迷惑
int* pa = const_cast<int*>(&a); // c++中专业的去常属性的操作符
d reinterpret_cast<类型>(变量)// 将指针变为整数,将整数转换为地址,即对内存进行重新解释,相当暴力。
又一天结束了。