0
点赞
收藏
分享

微信扫一扫

c++primer_基础

我是小瘦子哟 2022-02-05 阅读 43

第一章:开始

1.1编写一个简单的C++程序

函数定义包括哪四个部分?
return类型和函数返回类型“相容”是什么意思?#
数据、变量、类型的关系是什么?

iostream库中的stream如何理解?
iostream库中的四个对象,注意不是类

对象名功能
cin标准输入
cout标准输出
cerr标准错误
clog一般信息
#include <iostream>

这里的iostream是头文件还是源文件?
"<<"是一个什么运算符?左右两侧的“类型”要求是什么?运算返回结果是什么?

">>"是什么运算符?左右“类型”要求是什么?

如何理解“字符串字面值常量”?#
endl作为一个操纵符,它操纵了什么?

如何理解刷新缓冲区?

std是一个命名空间,作用是什么?
作用域运算符“::”的作用是什么?

单行注释结束符是什么?
多行注释可嵌套吗?为什么?
多行注释应该采取什么风格,让多行注释更加显眼?
在什么情况下可能会发生对多行注释的嵌套?如何进行?

控制流的部分跳过。
类的简单介绍跳过。

第二章:变量和基本类型

2.1 基本内置类型

基本数据类型包括哪些?算术类型+空类型(void)
算术类型包括哪些?字符、整型数、布尔值、浮点数。
空类型有哪些使用场景?

2.1.1 算术类型

算术类型的大小是固定的吗?

四种char的区别?

整型的区别?

阅读34页“内置类型的机器实现”,回答问题:
各种内置类型在机器层面的形式是什么?0和1
既然不同内置类型在机器层面的形式相同,那么如何进行区分?

浮点型:(一般情况下)
fload : 一个字(转换为十进制约有7个有效位)
double : 两个字(转换为十进制约有16个有效位)
long double : 三或四个字

signed和unsigned可以加在int \ short \ long \ long long 之前,表示有符号、无符号,如果不加,默认有符号

signed和unsigned可以加载char之前,表示有符号、无符号,如果不加,并不是默认有符号

数据类型选择的建议!
1、在满足条件的情况下,尽量选择无符号类型
2、在int范围不够的情况下,尽量选择long long
3、不要用char进行数值计算。
4、对于较小的整数,最好明确指定有无符号
5、浮点运算尽量使用double
说明:
1、无符号类型范围较大。
2、long类型和int类型常常有一样的尺寸。
3、char类型有时是有符号的,有时又是无符号的。
4、float通常精度不够,在运算上也不比double有很大的优势。

2.1.2 类型转换

如果无符号数和有符号数混合计算会发生什么?

无符号数和无符号数计算应该注意什么?

此外,无符号数++,无符号数–也应当注意在>=0的范围内进行计算。
整型字面值有无类型?是什么类型?

字符串对应什么数据结构?为什么实际长度比内容多1?

字符串分行书写的方式:
"first line "
“and second line”

常见的转义字符有:
换行\n 横向制表\t 报警\a 退格\b 双引号" 单引号’ 反斜线\ 问号? 回车\r

字面值的内容跳过

2.2 变量

2.2.1 变量定义

定义时可以不进行初始化,但是初始化必须在定义时进行。

初始化和赋值的区别是什么?

什么是默认初始化?

默认初始化在什么情况下不会发生?会造成什么影响?

介绍一种特殊的初始化形式:列表初始化,它使用花括号来进行初始化。

2.2.2 变量声明和定义的关系

分离式编译,如何理解?

分离式编译,如何实现?为什么?

声明和定义的区别?

变量只能被定义一次,但是可以被多次声明

静态类型,在编译阶段检查类型。编译器在对象处在错误的运算语句中时能够及时发现,前提是让编译器事先知道该对象的类型。这也是先声明后使用的原因。

2.2.3 标识符

大小写、不与语言自带标识符冲突、不能连续两个下划线
下划线不能紧连大写字母

命名规范:

  • 见名知义
  • 变量名消息字母
  • 类名大写字母开头
  • 多个单词之间应当区分,比如加下划线或者采用驼峰命名

2.2.4 作用域

作用域:变量有效的区域,大多以花括号分割。

作用域可以嵌套,内外层出现同名变量时(我们应当避免这种情况发生),优先访问内层变量,内层如果想要访问全局变量,可以使用作用域操作符双冒号::来访问,::左侧为空说明想要访问全局变量。

2.3 复合类型

2.3.1 引用

引用相当于给对象起一个别名。
引用必须初始化,绑定对象(引用初始化)是一个引用的使命。诞生之初就要明确,且绑定的对象不得更改。
注意:

  • 不能定义引用的引用(引用本身不是对象,只是一个名字)
  • 引用不能绑定字面值(只能绑定对象)

2.3.2 指针

指针和引用对比

引用指针
不是对象,只是一个名字是一个对象
必须初始化可以不初始化
不可更改引用的对象可以更改指向的对象

“&”

语句:
int age = 20;
int &refAge = age;
int *pAge = &age ;
int ageValue = *pAge ;

指针4种状态

  • 指向一个对象
    • 可以通过指针来间接访问对象
  • 指向对象的下一个位置
  • 空指针
    • 这两种情况虽然没有指向任何对象,但是是有效指针。
  • 无效指针
    • 可能会在编译器不觉察的情况下,造成严重后果,因为它在错误的使用下会修改我们本不希望修改的内存数据。
    • 往往是程序崩溃的原因。又往往难以定位。
    • 一种情况是:一个指针没有被初始化,那它就是无效指针。注意:空指针也需要初始化。虽然没有被初始化,但是很有可能程序在运行时发现这个指针指向一个对象!这会造成严重的后果。
    • 所以任何一个指针虽然不明确要求初始化,但是在编程时一定要及时赋值,实在不行就初始化为nullptr,避免无效指针引起程序崩溃。

指针的特殊使用

用在条件句中:if(pa) 如果pa是空指针,则返回false,如果指向一个对象则返回true
用在比较句中:if(pa==pb),返回true的条件

  • pa/pb存放的地址相同
    • 指向同一个对象
    • 指向同一个对象的下一个地址
  • 都为空

2.3.3 较复杂的情况

int a,*pA,&refA ;
//一句话声明了三个不同类型的变量:int、指针、引用
int a = 1;
int *pA = &a;
int *&p = pA;
//理解即可,最最好别这么写

2.4 const限定符

const对象必须初始化。

int i = 1;
const int j = i;
//这样做是可以的,含义是将当前i的值拷贝给const变量j
  • 编译器在编译的时候,将const类型的变量替换为对应的值。
  • 于是我们发现以下两个需求是冲突的:
    • 由于变量不允许重复定义,在一个文件中定义一个const类型的变量后,在其他文件中只能声明这个const类型的变量
    • 每一个文件必须能够访问到const变量对应的值,否则无法编译
  • 为了解决这个冲突,c++中默认设置为:const变量仅在本文件中有效。这样即使在多个文件中定义同一个变量也不会冲突。
  • 如果确实需要共享

2.4.1 const的引用

对const的引用,在定义时也需要声明为const:

const int num = 1;
const int &refNum = num; //对
int &refNum = num; //错
//引用const类型,则必须以这样的格式定义:const int &变量名 = 引用对象。这并不是说这个引用本身是个常量,而是说它指向const类型就应该这么写。这里const这个单词是修饰它指向的数据类型的,不是修饰它本身的。

int &refNum = 10; //错,引用的初始值必须是一个对象

const int num2 = 2;
refNum = num2; //错,引用不能更改

int num3 = 3;
const int &refNum3 = num3; //对,可以让refNum3自以为引用了一个常量

int &ref2Num3 = num3;
refNum3 = 10; //错,虽然num3本身不是const类型的,但是refNum3以为它是const类型的,所以不能通过refNum3来修改Num3
ref2Num3 = 10; //对,它不是const引用。
double dval = 1.1;
const int &ri = dval;
等价于:
double dval = 1.1;
int temp = dval; //temp = 1
const int &ri = temp;
//这是合法的,其中temp成为临时量。这里的temp只是帮助我们理解的,实际上它没有名字。但是不建议这样写,因为没有意义。

而对于不是const的情况:
int &refDval = dval;
这是非法的,由于临时量的存在,我们无法通过refDval来修改dval,这就使得这一引用毫无意义。

//如果绑定一个字面量:
const int &refInt = 10;
则也是创建了一个临时量temp=10供refInt来绑定。那么以下写法也是错误的,因为毫无意义
int &refInt2 = 10;

2.4.2 const和指针

一个指针可以认为它指向了一个const类型的变量,不管它是不是真的
最易混淆的是两种指针:指向常量的指针常量指针

指向常量的指针

const double dval = 3.14;
const double *pDval = &dval;
//将变量的地址赋予指针
//第二行中的const并不是修饰pDval本身的,而是说pDval的指向:指向一个常量
//任何一个指向常量的指针,都应该使用第二行这样的格式

//可以更换指向的对象,只要待更换的对象也是常量
const double dval2 = 11.1;
pDval = &dval2;

//不可以改变对象的值
*pDval = 22.2; //这是错误的

常量指针

int num = 1;
int *const pNum = &num;
//不可以更换指向的对象
//可以通过*pNum = 2;这样的方式来改变对象的值。

2.4.3 顶层底层const、指针之间的赋值

指向常量的常量指针:
const int *const pToConstNum = &num2;
这里第一个const是底层const,修饰所指对象,第二个是顶层const,修饰指针本身

(const int *) = (int *) :正确
(int *) = (const int *):错误
上面的两个const都是底层const,这体现了底层const对指针之间赋值操作的限制。

2.4.4 constexpr、常量表达式、字面值类型

什么是常量表达式?

常量表达式最简单的举例:字面量

const int a = 1;	//是
const int b = a+1;	//是
int c = 1;	//不是
const int d = getNum();	//不是

getNum()会随着运行而改变,在编译期间不能得到计算结果。

constexpr

constexpr int e = getNum();	
//只有当getNum()不随着运行而改变、在编译期就能得到计算结果时,这条语句才是正确的。
//当满足这个条件时,尽量将语句添加constexpr声明而不是用const,这样可以减少程序错误,增加可读性,便于优化。

字面值类型

值很简单的类型。
比如:int / long / short / double / bool 这些算术类型
比如:int &refNum 这种引用类型
比如:int *pNum 这种指针类型

值不简单的类型不是字面值类型:
比如:类(对象)、string类型

constexpr指针它的初始值必须是以下三种情况:

  • nullptr
  • 0
  • 固定地址中的对象

constexpr指针声明方式:虽然声明在底层const的位置,但是作用相当于一个顶层const,不许修改所指的对象:

constexpr int *q = nullptr;

2.5 处理类型

2.5.1 类型别名

typedef int size; //基本类型
typedef size *pSize; //复合类型
using count = size; //新的写法

难点在于处理复合类型比如指针的情况:

比如:复合再复合

typedef int *pInt;
pInt *ppInt;
//这里的ppInt是一个指向指针的指针(二维)

再比如:复合加const

typedef char *pString;
const pString cpStr;
//这里的cpStr是一个常量指针,而不是指向常量的指针

2.5.2 auto类型说明符

auto的作用:
编译器通过初始值来推算变量的类型。

int a = 1, b = 2, &d = a;
auto c = a + b;
//则推算c的类型为int

auto c = a + b, c2 = 1.1;
//错误,因为c是整型而c2是浮点型,不一致。
//这是一条声明语句,一条声明语句只能有一个基本数据类型

//auto特点:忽略顶层const,推算底层const
auto left( int ) = right( int );

auto left( int ) = right( const int );	//忽略顶层const
const auto left( int ) = right( int );	//显式说明顶层const

auto left( int 星 ) = &right( int );	//推断指针的方式
auto left( const int 星 ) = &right( const int );	//指针的底层const
const auto left( int 星 ) = right( int 星 );	//指针的顶层const
const auto left( int 星 ) = &right( int );	//指针的顶层const

auto left( int ) = right( int & );	//引用符号&被忽略,想使用引用只能用下面的方法
auto &refRight ( int & ) = right( int );	//绑定
const auto &refRight (  const int & ) = right( int / const int / 字面值 );	//引用的底层const

decltype 类型指示符

decltype() 不会对顶层const进行特殊处理,也不会消除引用
decltype() 可以传入表达式,包括函数:func(),注意写上括号
特殊的表达式包括:
decltype(整型引用) 整型引用
decltype(整型引用 + 整型) 整型
decltype(整型解引用) 整型引用
decltype((整型)) 整型引用

decltype(值):不加括号看作值
decltype((表达式)):加一层或多层括号看作表达式
在这里插入图片描述

举报

相关推荐

0 条评论