设为首页 加入收藏

TOP

现代C++学习指南-类型系统(一)
2023-07-23 13:28:33 】 浏览:79
Tags:现代 习指南

在前一篇,我们提供了一个方向性的指南,但是学什么,怎么学却没有详细展开。本篇将在前文的基础上,着重介绍下怎样学习C++的类型系统。

写在前面

在进入类型系统之前,我们应该先达成一项共识——尽可能使用C++的现代语法。众所周知,出于兼容性的考虑,C++中很多语法都是合法的。但是随着新版本的推出,有些语法可能是不推荐或者是需要避免使用的。所以本篇也尽可能采用推荐的语法形式(基于C++11或以上版本),这也是现代C++标题的含义。

采用现代语法有两点好处。其一,现代语法可以编译出更快更健壮的代码。编译器也是随着语言的发展而发展的,现代语法可以在一定程度上帮助编译器做更好的优化。其二,现代语法通常更简洁,更直观,也更统一,有助于增强可读性和可维护性。
明确了这点后,让我们一起踏入现代C++的大门吧。

类型系统

程序是一种计算工具,根据输入,和预定义的计算方法,产生计算结果。当程序运行起来后,这三者都需要在内存中表示成合适的值才能让程序正常工作,负责解释的这套工具就是类型系统。数字,字符串,键盘鼠标事件等都是数据,而且在内存中实际存在的形式也是一样的,但是按我们人类的眼光来看的话,对它们的处理是不一样的。数字能进行加减乘除等算术运算,但是对字符串进行算术运算就没有意义,而键盘鼠标的值通常只是读取,不进行计算的。正是由于这些差异,编程语言的第一个任务就是需要定义一套类型系统,告诉计算机怎样处理内存中的数据。
为了让编程语言尽可能简单,编程语言一般把类型系统分为两步实现,一部分是编译器,另一部分是类型。编译器那部分负责将开发者的代码解释成合适的形式,以便可以高效,准确在内存中表示。类型部分则定义一些编译器能处理的类型,以便开发者可以找到合适的数据来完成输入输出的表示和计算方法的描述。这两者相辅相成,相互成就。
类型作为类型系统的重要表现形式,在编程语言中的重要性也就不言而喻了。如果把写程序看成是搭积木的话,那么程序的积木就是类型系统。类型系统是开发者能操作的最小单位,它限制了开发者的操作规则,但是提供了无限的可能。C++有着比积木更灵活的类型系统。

类型

类型是编程语言的最小单位,任何一句代码都是一种内存使用形式。
而谈到C++的类型也就不得不谈到它的三种类型表现形式——普通类型,指针,引用。它们是三种不同的内存使用和解释形式,也是C++的最基础的形式。和大部分编程语言不同,C++对内置类型没有做特权处理,只要开发者愿意,所有的类型都可以有一致的语法形式(通过运算符重载),所以下面关于类型的举例适合所有的类型。
普通类型就是没有修饰的类型,如int,long,double等。它们是按值传递的,也就是赋值和函数传参是拷贝一份值,对拷贝后的值进行操作,不会再影响到老值。

int a=1; //老值,存在地址1
int b=a; //新值,存在地址2
b=2; //改变新值,改变地址2
//此时a还是1,b变成了2

那假如我们需要修改老值呢,有两种途径,一种是指针,另一种则是引用。
指针是C/C++里面的魔法,一切皆可指针。指针包含两个方面,一方面它是指一块内存,另一方面它可以指允许对这块内存进行的操作。指针的值是一块内存地址,操作指针,操作的是它指向的那块地址。

int a=1; //老值,存在地址1
int* b=&a; //&代表取地址,从右往左读,取a的地址——地址1,存在地址2
*b=2; //*是解引用,意思是把存在地址2(b)的值取出来,并把那个地址(地址1)的值改成2
//此时a,*b变成了2


引用则是指针的改进版,引用能避免无效引用,不过引用不能重设,比指针缺少一定的灵活性。

int a=1; //老值,存在地址1
int& b=a; //&出现在变量声明的位置,代表该变量是引用变量,引用变量必须在声明时初始化
b=2; //可以像普通变量一样操作引用变量,同时,对它的操作也会反应到原始对象上
//此时a,b变成了2

变量定义

类型仅仅是一种语法定义,而要真正使用这种定义,我们需要用类型来定义变量,即变量定义。
C++变量定义是以下形式:

type name[{initial_value}]

这里的关键在于typetype是类型和限定符的组合。看下面的例子:

int a; //普通整型
int* b; //类型是int和*的组合,组成了整型指针
const int* c; //从右往左读,*是指针,const int是常量整型,组成了指向常量整型的指针类型
int *const d; //也是从右往左读,const是常量,后面是指针,说明这个指针是常量指针,指向最左边的int,组成常量指针指向整型
int& e=a; //类型是int和&的组合,组成了整型引用
constexpr int f=a+e; //constexpr代表这个变量需要在编译期求值,并且不再可变。

以上,基本就是变量定义的所有形式了,类型确定了变量的基本属性,而限定符限定了变量的使用范围。
定义变量也是按照这个步骤进行,首先确定我们需要什么类型的变量,其次再进一步确定是否需要对这个变量添加限定,很多时候是需要的。可以按以下步骤来确定添加什么样的限定符:

  1. 是个大对象,可以考虑把变量声明成引用类型。通常引用类型是比指针类型更优的选择。
  2. 大对象可能需要被重置,可以考虑声明为指针。
  3. 只想要个常量,添加constexpr
  4. 只想读这个变量,添加const

变量初始化

变量定义往往伴随着初始化,这对于局部变量来说很重要,因为局部变量的初值是不确定的,在没有对变量进行有效初始化前就使用变量,会导致不可控的问题。所以严格来说,前面的变量定义是不完全正确的。
C++11推出了全新的,统一的初始化方式,即在变量名后面跟着大括号,大括号里包着初始化的值。这种方式可以用在任何变量上,称之为统一初始化,如:

int a{9527}; //普通类型
string b={"abc"}; //另一种写法,等价但是不推荐
Student c{"张三","20220226",18}; //大括号中是构造函数参数

当然,除了用类型名来定义变量外,还可以将定义和初始化合二为一,变成下面这种最简洁的形式:

auto a={1}; //推导为整型
auto b=string{"abc"}; 
auto c=Student{"张三","20220226",18}

这里auto是让编译器自己确定类型的意思。上面这种写法是完全利用了C++的类型推导,这也是好多现代语言推荐的形式。不过需要注意的是,使用类型推导后,=就不能省略了。
有了初始化的变量后,我们就可以用它们完成各种计算任务了。C++为开发者实现了很多内置的计算支持。如数字的加减乘除运算,数组的索引,指针的操作等。还提供了分支ifswitch,循环whilefor等语句,为我们提供了更灵活的操作。

函数

变量是编程语言中的最小单位,随着业务的复杂度增加,有些时候中间计算会分散业务的逻辑,增加复杂度。为了更好地组织代码,类型系统增加了 函数来解决这个问题。
函数也是类型,是一种复合类型。它的类型由参数列表,返回值组合而成,

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇驱动开发:内核遍历文件或目录 下一篇C++面试八股文:什么是RAII?

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目