首页 > 编程语言 >c++ primer ch2笔记

c++ primer ch2笔记

时间:2024-02-28 19:26:37浏览次数:17  
标签:const int c++ 对象 ch2 引用 类型 primer 指针

ch2

2.1 基本内置类型

C++基本内置类型

  • void

  • 算术类型

    • 整形(包括字符,bool)

    • 浮点型

最小尺寸:

  • 整形尺寸大小受编译器影响,但是至少会保证一个最小尺寸,int最小尺寸2字节

  • 相互关系:int至少和一个short一样大

无符号类型:unsigned int、unsigned long

类型转换规则:

  • 布尔<->非布尔

  • 整形<->浮点型

  • unsigned超过最大表示范围:对无符号表示范围取模后的余数

  • 带符号超过最大表示范围:未定义

对无符号的计算应谨慎:

算术表达式兼有signed 、unsigned,将结果转成unsigned

unsigned u = 10, u2 = 42;
std::cout << u2 - u << std::endl; //32
std::cout << u - u2 << std::endl; //4294967264超过无符号表示范围,取余

字面值:

  • 不同进制的整形字面量

  • 浮点字面量的指数(1E3)

  • 字符串""、字符''、转义字符、泛化转义序列(\x+16进制数字 or +8进制数字)

  • 布尔、指针字面量

字面值类型:没找到准确定义,,姑且看作是可以用字面值体现的类型,包括算术类型、指针、引用+一部分满足要求的类(字面值常量类,7.5介绍)。string不是字面值类型。

2.2 变量

变量初始化定义:创建时获得一个特定值

初始化方式:

  • 默认初始化(创建时未被指定类型)

    • 基本类型:由定义位置决定,函数体外的基本类型对象默认初始化为0;函数体内未定义

    • 其他类型:由具体类的实现方式决定,String会被初始化为空串

  • 列表初始化(基本类型&&存在丢失信息风险=》编译报错)

声明和定义区别:定义需要申请存储空间,可能还要进行初始化操作

如何表示声明?加extern关键字

int j;//定义
extern int j;//声明

为什么区分声明和定义?

为支持分离编译,多个文件要使用同一个变量就必须将声明和定义分离。a文件要用b文件定义的变量,必须声明一下那个变量。一个变量可以被声明多次,但是只能被定义一次。

引用作用域外的对象

int i = 42;
int main()
{
  int i = 40;
  std::cout << i << endl;//40
  std::cout << ::i << endl; //42
}

 

 

2.3 复合类型

引用:对象的别名,本身不是对象。

指针:是对象,指向对象的地址。

类型定义方式类型要求初始化要求常见操作
引用 int &rval = val; 除两种情况外,引用类型必须和对象类型相匹配(int类型的引用的右值必须是int类型) 必须直接初始化右值不能是字面量 对rval操作就是在操作val引用是可以绑定到其他对象上的
指针 int *p = &val 除两种情况外,指针类型必须和对象类型相匹配(int类型的指针的右值必须是int类型) 不必直接初始化,块作用域内定义的指针没有显示初始化会是一个不确定的值可使用nullptr初始化指针 解引用比较操作(地址相等返回true,指向某个对象和指向另外对象下一个地址也可能返回true)

 

 

2.4 const限定符

常量,不可以被改变。

const对象必须被初始化,可以用const对象去初始化别人。

为什么const对象仅在文件内有效?

因为编译器会把const变量替换成常量 -> 编译器需要找到const变量的定义位置 -所以默认文件内有效。不同文件中定义的同名const变量被认为是独立的。

如何做到跨文件共享const变量?对const变量的声明和定义都加上extern。

初始化的常量引用和常量指针可以引用类型不相同的对象。

double d = 3.14;
const int & r = d;//可以,r的取值是3,存在精度损失

原因:编译时一旦出现类型不匹配,编译器的行为是先生成一个与引用/指针类型相同的临时量,然后让引用/指针去引用/指向这个临时量。对于非const的引用/指针,他们被绑给了一个临时量而不是原始对象,不符合语义,所以报错;对于const的引用/指针,反正也不会通过它们修改对象值,指向临时量和指向原始对象没差别,所以这种情况不会报错而是允许const引用/指针绑给一个精度出现损伤的临时量。

引用、指针与const的关系:

  • const引用/指针可以作为const对象的左值

  • 非const引用/指针可以作为非const对象的左值

  • const引用/指针可以作为非const对象的左值

  • 非const引用/指针不可以作为const对象的左值

上面关键在于第4点,const引用/指针可以引用非常量对象,只要不保证通过这个常量的引用/指针去改变对象就行,其他引用/指针修改对象也管不了;但是运行非const去引用const那就意味着允许通过它去修改对象,编译器会报错。

顶层const(int * const p):指针本身指向的地址不可以修改

底层const(const int * p):指针指向的地址的值不可以修改

执行拷贝操作时拷贝考出的对象要具备相同的底层const资格,这其实体现了上面那四条关系,避免拷贝时出现非const引用const的情况。

对常量的取址操作返回结果可以用什么引用?

const对象的取值只能用底层const引用

const double d = 3.14;
const double * p = &d;//ok
double * p =  &d;//wrong
double * const p = &d;//wrong

 

常量表达式:编译时就能得到计算结果的表达式(字面值以及字面值初始化的const变量)。

下面的公式不是常量表达式,因为getSize需要运算才能得到结果

const int size = getSize();

如何声明一个常量表达式?

声明为constexpr后编译器会对getSize进行检查,如果getSize是constexpr函数的话拿它就是常量表达式

constexpr int size = getSize();

constexpr的作用范围:仅限字面值类型,包括算术类型、引用、指针等,不能用于声明string等自定义类型。

constexpr与指针:

  • 指针可以声明为constexpr类型,它的语义是这个指针指向的位置不可变(顶层const)

  • constexpr指针的初始值受到严格限制,只能是0,nullptr或指向固定地址的指针(在函数方法里定义的指针指向位置经常变,不能声明为constexpr)

2.5 处理类型

定义类型别名

  • typedef关键字

  • using关键字

解读指针类型的别名是千万不要直接做个替换就开始读了!!!

str是什么类型?

typedef char* pstring;
const pstring str = 0;

不要解读为const char * str = 0;这样str就是指向char常量的指针了。实际情况是const是修饰char *的,表示这个指针是常量(顶层const),而不是指针指向的对象是const。

类型推断之auto:

让编译器去分析所属类型。一个auto语句后面可以声明多个变量,必须保证基本类型是一致的(比如同是int类型、int类型引用或int类型指针)

auto推断的两个特点:

  • auto a = r;r是引用类型时(int &),a会被推断为基本类型(int)

  • auto一般会推断出底层const,无法推断出顶层const,如要保留顶层const特性可以手动加const

const int p = 0;
int p3 = 0;
int const * pp = &p3;
const int & p2 = p;
auto d = p;//p是顶层const,这里的d丢失了顶层const特性,只是int类型
auto a = &p;//&p只能用const int引用,是底层const,底层const被保留,a是const int*类型
auto b = pp;//b是const int *类型,这里pp是顶层引用,但是也可以保留
auto c = p2;//c是int类型,顶层const信息丢失
const auto f = p2;//f是const int,手动加const

类型推断之decltype:

decltype(表达式) a,那么a就是表达式的返回类型。

它和auto的区别:

  • 可以推断出引用类型(int &r = v;decltype(r) j;这里j是int &而不是int)

  • 可以推断出顶层const

此外还有一些特点

  • decltype(引用和基本类型的算术表达式,如int & + 0),那么最后实际类型是基本类型

  • decltype(解引用操作),最后返回的是引用类型

练习2.37:decltype(a = b),实际上a = b并没有执行。

2.6 自定义数据结构

定义struct类型的方式。

使用头文件:在头文件中定义类,这样通过include头文件的方式就可在不同文件中使用这个类了。

预处理器:编译之前执行的一段程序,会改变我们所写的程序。它对头文件的影响:

  • 对cpp文件:用头文件内容代替#include

  • 对头文件:使用头文件保护符#define、#ifdef等,写在头文件的类的定义周围;避免头文件被重复定义。良好的代码习惯要求加上这些保护符。

预处理变量:不属于任何命名空间,前面无需加std::

标签:const,int,c++,对象,ch2,引用,类型,primer,指针
From: https://www.cnblogs.com/ljf-0/p/18041486

相关文章

  • rust与python/c++语法区别
    if/matchpubfnanimal_habitat(animal:&str)->&'staticstr{letid=ifanimal=="crab"{//id等于(或拥有)了一个匿名函数的返回值1}elseifanimal=="gopher"{2}elseifanimal=="snake"......
  • C++的异常处理究竟有多慢?
    我们能在各处看到“C++的异常很慢,不要用”这样的言论,不过很少有人告诉你,C++的异常到底有多慢,以及它为什么这么慢。本文会详细介绍C++在抛出以及捕获异常时,代码到底做了什么,以及我们使用C++异常到底付出了多少代价。抛出异常要了解异常处理到底做了什么,我们需要深入到汇编语言来......
  • 通过前向声明解决C++中两个头文件互相引用的问题
    在C++中,当两个头文件互相引用时,可以通过前向声明来避免直接的#include依赖,从而解决循环依赖的问题。前向声明是在一个头文件中声明另一个头文件中的类或类型的名称,而不包括其具体的实现细节。这样,每个头文件只依赖对方的声明,而不需要依赖对方的定义,从而打破了循环依赖。以下是如......
  • OpenCV计数应用 c++(QT)
    一、前言为了挑战一下OpenCV的学习成果,最经一直在找各类项目进行实践。机缘巧合之下,得到了以下的需求:要求从以下图片中找出所有的近似矩形的点并计数,重叠点需要拆分单独计数。二、解题思路1.图片作二值化处理autoimage=cv::imread("points.jpg");cv::Matborder;//为......
  • C++临时对象
    C++临时对象临时对象的构造与析构在C++中,临时对象(TemporaryObject)是在表达式求值过程中创建的、无名字的对象。它们通常用于存储中间结果或作为函数调用的参数或返回值,其生命周期通常仅限于表达式的求值过程中。临时对象的构建和析构与普通对象类似,只是它们的生命周期通常比......
  • C++ 点的线性拟合 y(x)=ax+b
    一、简单分析点的线性拟合是一般实验数据处理最常用的方法。下面考虑一个用n个数据点拟合成直线的问题,直线模型为y(x)=ax+b这个问题称为线性回归。设变量y随自变量x变化,给定n组观测数据(xi,yi),用直线来拟合这些点,其中a,b是直线的斜率和截距,称为回归系数。为确定......
  • 微软 官方 .net 组件 下载 directx组件 下载 viual c++ 组件 下载 官方 修复DLL方
    下载.NETFramework|免费官方下载(microsoft.com).NETFramework是仅适用于Windows版本的.NET,用于生成客户端和服务器应用程序。升级应用在VisualStudio中单击几下即可将应用从.NETFramework升级到最新的.NET。  DownloadDirectXEnd-UserRuntimefromO......
  • nginx支持cgi(c,c++)
    前段时间用我修改了tinyhttpd,让其cgi支持文件流,感觉满小巧,就应用上了。最近访问请求量上来而来,它对socket的各种异常状态处理不好,对于慢速的链接会占用我的线程。虽然我一直想仿出tencentwebproxy,可惜人懒且没空。用用nginx也不错,配置其支持fcgi,应用代码稍微改改就支持了,效果很不......
  • c++的oop之class和struct
    c++中的面向对象构造函数与C#一样,可以拥有多个构造函数,但python只有一个构造函数默认的无参构造函数,可以这样写classname()=default;构造函数时初始化变量,建议这样写。对于const或自定义类型必须这样写,而对于内置类型几乎是一样的。MyClass::MyClass(stringname,intid):......
  • C++多态
    /**多态/动态调用***1.虚函数/虚拟函数*语法:在函数前面加上virtual**1.1虚函数与虚继承没有关系,只是共用了关键字**2.重写/覆盖:虚函数且函数名字类型等完全一样*$注:虚函数是覆盖,不是虚函数才构成隐藏*$重写:指对函数体重写,函数体外的是直接使用父类的,......