1、const 和 指针 的关系
1.1 基本情况
const 指针的关系主要存存在三种:
1、常指针(const pointer)
int* const p;
2、指针类型的常量(const to pointer)
const int *p;
int const *p;
3、指向常量的常指针
const int * const p;
那么这三种不同的类型是如何使用的呢?首先我们来看下面的代码:
#include<iostream>
using namespace std;
int main()
{
int a = 10;
int b = 20;
int *p1 = &a;
int * const p2 = &a;
const int * p3 = &a;
const int * const p4 = &a;
return 0;
}
1、常指针的修改
int main()
{
cout << *p2 << endl;
*p2 = b;
cout << *p2 << endl;
p2 = &b;
}
我们可以发现,在const 修饰指针本身的时候(int *const p2)。我们可以修改指针解引用后的值,但是不能修改指针本身所指向的地址。
2、指针类型的常量的修改
int main()
{
cout << *p3 << endl;
cout << *p3 << endl;
p3 = &b;
cout << *p3 << endl;
}
当指针是一个指向常量的指针时(const int *p3)。我们可以改变指针所指向的对象,但是不能修改指针解引用后的值。
3、指向常量的常指针修改
*p4 = b;
p4 = &b;
当指针是指向常量的常指针的时候,我们既不能修改指针本身,又不能修改指针解引用后的值。
1.2 常指针或者指针类型的常量
1.2.1 常指针 const int *p = &a;
int main()
{
int a = 10;
int b = 20;
const int *p = &a;
const int *s1 = p;
const int *const s3 = p;
return 0;
}
1.2.2 指针类型的常量 int * const p = &a;
int main()
{
int a = 10;
int b = 20;
int * const p = &a;
int *s0 = p;
const int *s1 = p;
int * const s2 = p;
const int *const s3 = p;
system("Pause");
return 0;
}
int *const p = &a; 这条代码表示p是一个常指针,这个指针所指向的是地址不可改变的。这个常指针存放的是a的地址。其他的指针指向的也是a的地址,这些指针的赋值是正确的。因为常指针仅仅只是规定指针p不可以指向其他的地址,并没有规定其他指针不能改变这个指针解引用的值。况且其他指针的修改也仅仅只是修改这些指针本身(s0、s1、s2、s3)解引用的值(p的值)或者指向的地址,编译可以正常通过。
1.3 const_cast
首先来看一个概念:只读变量(常变量)。
const int n = 5;
int a[n];
所以说,在C++中我们会将常变量看作为常量。
int main()
{
const int a = 10;
int b = 20;
int *p = &a;
*p = b;
}
这段代码编译器会报错,原因如下:
要解决可以使用 C++的标准转换运算符const_cast。
C++提供了四个转换运算符来移除变量的const限定符:
- const_cast (expression)
- static_cast <new_type> (expression)
- reinterpret_cast <new_type> (expression)
- dynamic_cast <new_type> (expression)
只需将代码改为 int *p = const_cast<int *>(&a); 即可移除变量a的const 限定符,实现初始化。
2、const 和引用 的关系
2.1 什么是引用
引用就是某个变量的别名,对引用的操作对与变量的直接操作完全相同。
格式为:类型 & 引用变量名 = 已定义过的变量名。
2.2 引用和指针的区别
引用 | 指针 |
---|
必须初始化 | 可以不初始化 | 不可为空 | 可以为空 | 不能更换目标 | 可以更换目标 | 没有二级引用 | 存在二级指针 |
1、引用必须初始化,而指针可以不初始化
int &s;
int *p;
2、引用不可以为空,指针可以为空
int &s = NULL;
int *p = NULL;
int fun_p(int *p)
{
if(p != NULL)
{
cout << *p << endl;
}
return *p;
}
int fun_s(int &s)
{
cout << s << endl;
return s;
}
3、引用不能改变目标,指针可以更换目标
int main()
{
int a = 20;
int b = 10;
int &s = a;
int *p = &a;
s = b;
p = &b;
cout << s << endl;
cout << a << endl;
system("pause");
return 0;
}
2.3 指针和引用性能差异
指针:
void fun_p(int *p)
{
*p = 10;
return;
}
int main()
{
int a = 20;
int *p = &a;
fun_p(p);
}
通过objdump -d 命令来查看指针的反汇编代码:
引用:
void fun_s(int &s)
{
s = 10;
return;
}
int main()
{
int a = 20;
int &s = a;
fun_s(s);
}
通过objdump -d 命令来查看指针的反汇编代码:
我们可以清除的看出指针和引用的反汇编代码时基本一致的。这说明C++编译器在编译程序的时候将指针和引用编译成了完全一样的机器码。所以C++中的引用只是C++对指针操作的一个“语法糖”,在底层实现时C++编译器实现这两种操作的方法完全相同。
2.4 指针的引用
2.4.1 int *p = &a;
int main()
{
int a = 10;
int b = 20;
int *p = &a;
int *s = p;
const int *&pref3 = p;
p = &b;
int *const &pref4 = p;
*p = b;
const int *const &pref5 = p;
system("pause");
return 0;
}
2.4.2 const int *p = &a;
int main()
{
int a = 20;
int b = 10;
const int *p = &a;
int* &pref1 = p;
*pref1 = b;
const int* &pref2 = p;
int* const &pref3 = p;
const int* const &pref4 = p;
return 0;
}
未完… …
|