C++学习_引用和命名空间

引用

一。写在前面:
1. 引用的特性:

  • 引用在定义的时候必须初始化,并且只能“从一而终”。

  • 一个变量可以有多个引用(通常实体的声明周期比引用的声明周期长)

2.编译器不会为引用分配内存空间,它和它引用的变量共同使用同一块内存空间

二。常引用

注:这里指的是左值引用

两种类型
- const 类型& 引用变量名 = 实体变量名;
- const 类型& 引用变量名 = 常量;

普通引用只能引用同类型的实体,加上const限定符后就可以引用不同类型的实体,但是里面有一些细节(见下):

double d=12.34; //①
const int&rd = d; //②
d=10; //③
//rd=12;//④

代码说明:rd是d的引用,但是③后并没有改变rd的值,这是为什么呢?
①~②创建了一块临时的空间将d进行类型转换后的值放到了那块匿名空间,然后rd引用的是匿名空间中的,既然rd所引用的值和d的值都不在同一块地址空间,那么通过③自然无法修改rd引用的值了,而rd引用的值具有常性,所以也不可以通过④来修改,如果把④的注释去掉,则会出现编译错误

常引用的适用场景:做函数形参时,如果实参是输入形参数,则给引用加上const限定。

三。引用数组

定义实例:

int a[10];
int (&ra)[10]=a; //rd是整形数组a的引用
//int (&rra)[9]=a;//这是错误的引用

四。不能返回栈空间上的引用

代码示例:

int &Func(int a)
{
    return a;
}
void main(void)
{
    int b=10;
    int &rb=Func(b);
    printf("%d\n",rb);//打印出10
    printf("%d\n",rb);//打印出随机值
    printf("%d\n",rb);//打印出随机值
}

代码说明:函数Func在传参的时候,会建立一个临时的空间存储实参a,这个空间时在栈上获取的,而返回值是一个引用,这个引用的实体是栈空间上的值,而函数在执行结束后就会失去对刚才那块栈帧的控制(下次调用这个函数会重新开辟,不一定在原来的位置),而接受这个返回值的也是一个引用,所以当那块栈空间的内容被别的函数帧栈覆盖后,a的值就变成了一个垃圾值,所以后面的两次打印就会打印出随机值,那么为什么第一次打印出的是10呢?因为C++/C的函数调用约定默认都是_cdecl,这种调用约定规定参数从右向左入栈,所以第一次先将rb(第一次也就是未改变之前的a)压栈,然后才会覆盖掉之前函数调用的栈帧结构,所以第一次会打印出正确的值10.

注:如果不用引用来接收栈上的返回引用,则不会出现上面的问题,eg:
int a=Func();


关于这个问题的建议:如果函数的返回值是引用类型,那么返回值的生命周期一定要长于函数的生命周期
解决方案:
1. 返回全局变量
2. int Func(int &a) { return a; }
3. 返回在函数中定义的静态变量(static)

第三条说明:一般在设计函数的时候不推荐设计带有记忆功能的函数(除非特殊需要),相同输入应该产生相同的输出,而使用static就是典型的记忆型函数设计。

五。指针和引用的区别
1. 初始化要求不同,引用在定义的时候必须初始化
2. 引用只能从一而终,而指针不是
3. 看代码:

//一个改变指针指向,一个改变变量内容
int *p1=a;
int &p2=a;
p1++;//指针向后偏移
p2++;//a自加1

4.sizeof(指针变量)和sizeof(引用变量):前者在32位机器下都是4个字节,后者是所引用的变量的大小
5. 有多级指针,但是无多级引用
6. 引用自动寻址,而指针需要手动寻址

命名空间

  1. 命名空间的作用

    一个中大型软件往往由多名程序员共同开发,会使用大量的变量和函数,不可避免地会出现变量或函数的命名冲突。当所有人的代码都测试通过,没有问题时,将它们结合到一起就有可能会出现命名冲突
    例如: A和B都参与了一个文件管理系统的开发,它们都定义了一个全局变量 fp,用来指明当前打开的文件,将他们的代码整合在一起编译时,很明显编译器会提示 fp 重复定义(Redefinition)错误。
    为了解决合作开发时的命名冲突问题,C++ 引入了命名空间(Namespace)的概念。

  2. 定义格式:
    namespace name{
    //variables, functions, classes
    }

    name是命名空间的名字,花括号里边就是这个命名空间的内容,它里面可以包含变量、函数、类、typedef、#define 等。

  3. 使用格式:
    1> 第一种就是直接加域解析符(::),eg:

    using Li :: fp;
    fp = fopen("one.txt", "r");  //使用小李定义的变量 fp
    Han :: fp = fopen("two.txt", "rb+");  //使用小韩定义的变量 fp
    

这种方式的使用命名空间中的内容有一种明显的缺点:每一次使用命名空间中的内容都需要显式的将所属于的命名空间写出来,如果需要操作很多内容,很多次,那这样就会非常麻烦!

2>第二种就是使用using,在使用某一个命名空间的源文件前加上
using namespace name //name就是指定的命名空间名,eg:std

4.命名空间可以嵌套:a::b::c
5. 命名空间可以重名
6. 匿名命名空间里的成员只能在声明该匿名空间的文件内使用(作为全局变量)

Else

  1. 如何知道结构体中某个成员相对结构体起始位置的偏移量?

    使用offsetof(),它返回某个成员相对于起始地址的偏移量

    注:这是一个宏,定义在stddef.h内,只能访问c++中class的public类型成员和struct中的全部成员

  2. 复习柔性数组并修正于
    https://blog.csdn.net/zanda_/article/details/78700016#t8

  3. 又掌握了一种测试当前机器大小端的方式

    #include <stdio.h> 
    int main(int argc, char *argv[])  
    {  
        int i = 0x12345678;  
        char c = i;  
        //大端:输出12 | 小端:输出78
        printf("%x \n", c);  
        return 0;  
    }     
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值