栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++基础第2章:对象与基本类型(2)——指针、引用/常量、常量表达式

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++基础第2章:对象与基本类型(2)——指针、引用/常量、常量表达式

文章目录
  • 1.复合类型:从指针到引用
    • 1.1.指针
    • 1.2.引用
  • 2.常量类型与常量表达式
    • 2.1.常量指针
    • 2.2.常量引用
    • 2.3.常量表达式

1.复合类型:从指针到引用 1.1.指针

注意 :既然指针具有相同的尺寸,为什么还要区分不同类型的指针呢?比如int* p1; char* p2,这是因为指针中存储的是一个内存地址,内存地址的长度都是一样的,所以指针是具有相同的尺寸的。但是它存储的内存地址存储的变量是具有类型的,我们只是得到了这个变量的首地址,并不知道这个变量的尺寸,这样就无法访问这个变量了。比如int*要从内存地址开始访问4个字节,char*从内存地址开始访问一个字节。所以指针类型就是规定了指针所指向对象的长度。


1.2.引用

2.常量类型与常量表达式 2.1.常量指针


注意:

  1. 常量指针可以指向变量的解释
// 1.常量指针可以指向变量,其中包含了一次隐式类型转换
// &x的类型是int*, 然后给他加一个const限制是合法的,所以这中间
// 有一个隐式类型转换,即int* 变成 const int*
int x = 0;
const int* p = &x;

// 2.反之不可以,即(变量)指针不能指向常量
// 下面这样&x的类型是const int*, 而p的类型是int*,这样隐式类型转换相
// 当于去掉了限制,因为后面可以用p对x进行写操作了,而原来x的定义是
// 没有写操作的,因此这种隐式类型转换是错误的
const int x = 0;
int* p = &x;
  1. 对const int*和int* const的理解可以这样看:
  • const int*对其解引用的话,得到的就是const int,因此这个指针所指向的内容是一个常量,是不能改的。
  • int* const对齐解引用的话,得到的就是int const,这个好像就没法解释了。所以只记住上面那个解释即可,上面那个解释是合理的。
2.2.常量引用
  1. const int&(也可绑定变量)
  • 这个地方和常量指针是一样的,因为引用的底层实现就是指针。
    但是和指针不同的是,只存在常量引用(const int&),不存在引用常量(int& const),因为引用的本身定义就是一个变量的别名,不能指向其他变量。
  • 同理常量引用可以绑定变量,因为这相当于给变量增加了限制。但是反过来,普通的引用不能绑定常量,即如下是非法的:
// 合法:常量引用绑定变量,相当于给变量提升限制
int x = 0;
const int& ref = x;
// 非法:普通引用绑定了常量,相当于给常量去掉了限制
const int x = 0;
int& ref = x;   
  1. 可读但不可写
    这个很显然
  2. 主要用于函数形参
    首先明确为什么要按引用传递:
    (1)自定义的数据类型,比如类和结构体可能比较大,如果使用普通的按值传递,那么赋值造成的成本很大。所以要避免复制。
    (2)如果使用指针传入,可以避免复制,但是指针不太安全,比如传入的可能是野指针等
    (3)使用引用解决了上述两个问题
    其次为什么要使用常量引用:
    防止在函数内部修改传入的量,保证安全性。

注意:不要把普通的int``bool类型也用引用来传递,因为这些内置类型拷贝的成本很低,如果使用引用,其内部实现还是指针,反而拷贝指针的时候需要8字节,其次访问指针的时候需要经过两次内存访问操作,性能更低。

  1. 可以绑定字面值
  • 首先明确普通的引用是不能绑定字面值的,因为字面值没有内存地址,所以引用无法起作用。
// 错误:普通引用不能绑定字面值
int& ref = 3;
  • 但是常量引用就可以绑定字面值,这个主要是C++中为了函数接口来使用的。比如下面的程序:
void fun(const int& param)
{

}

int main()
{
	int x = 3;
	fun(x);
	// 很多时候都会直接传入一个3调用,为了让这种代码合法,所以C++规定常量引用可以绑定字面值
	fun(3);  
2.3.常量表达式
  1. 使用 constexpr 声明
    如下程序所示,程序中确定一个常量,可以在不同的阶段确定。比如可以在程序编译期间就确定,也可以在程序的运行期间确定。
// 1.在运行期间确定常量
int x;
std::cin >> x;
const int y = x;

// 2.在编译期间确定常量
const int y = 3;
  1. 声明的是编译期常量
    从上面可以看出来,如果仅仅使用const,那么常量也可以在程序的运行期间定义。
    为了更加明确常量直接在编译期间确定,所以引入限定符constexpr,这样就明确的表示我定义的常量是在编译期间就确定的。

注意:constexpr只是一个限定符,它并属于一种对象类型。比如const int是常量的int类型,但是constexpr int它的类型仍然是const int,而constexpr的作用,除了声明了这个类型是const int之外,它还限定了这个常来类型的值是在编译期间就确定的,而不是运行期间。所以也可以简单的理解为,constexpr修饰的是定义变量的类型,也就是它直接修饰的是x变量。

// x的类型仍然是const int, 而不是constexpr int,因为constexpr并不是一种类型
constexpr int x = 1;
  1. 编译器可以利用其进行优化
    比如如果定义的是编译期间就确定的常量,那么很多代码在编译期间就可以被优化:
constexpr int y = 3;    // const int y = 3;
if(y == 3)
{
   ......
}

// 上面代码在编译期间可以优化成:
{
    ..... 
}
  1. 常量表达式指针: constexpr 位于 * 左侧,但表示指针是常量表达式
constexpr const int* p1 = nullptr;
constexpr const char* p2 = "123";

这里理解类型的时候和上面的2是一样的理解方法,注意3点:
(1)consexpr是限定符,不是类型;
(2)看类型的时候,constexpr等价于const;
(3)合起来看总的类型的时候,constexpr(等价于const类型)直接修饰的是变量x,所以要放在变量左边。

即上面的类型是const int* const和const char* const,前一个const是原来明确写的,后面的const是constexpr限定p1/p2得到的。

这里也可以发现,可能平常写的const int x,写成int const x意义更加明确一些,实际上在C++中这两种写法都是合法的,但是前者的写法更加常见。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1000982.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号