重新系统学习C++遇到的坑(系列二)(写了关于const和*(或&)的混合使用,该如何理解?)

  • 类型unsigned int可缩写成unsigned

  • int、char、double这些内置类型,实际上可以看成int类类型、char类类型、double类类型,因为类设计的目的之一是让我们能像使用C++内置类型一样自然地使用类

  • 负数转换为无符号数,结果等于这个负数对无符号类型表示的数值总数(看这个无符号类型所占字节,即2的几字节次方)取模后的余数

  • 2的32次方=4294967296

  • -32转换为无符号整型数为4294967264(负数加上无符号整型数能表示最大值),-1转换为无符号整型数为4294967295!

  • ‘a’和"a"是不一样的,‘a’只有一个字符a,而"a"有两个字符,分别是’a’和空字符’\0’

  • 初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值来替代。

  • 初始化每一个内置类型的变量

  • 全局作用域本身没有名字,所以如果想在块作用域(有和全局作用域的同名变量的话)访问全局作用域的同名变量,就这么写(也要会认):
    ::全局作用域的变量名

  • 最基本的一点:引用是为对象起了另外一个名字,且引用必须被初始化!

  • 定义引用(&),程序是把引用和它的初始值死绑一起,即不能让引用重新去和别的对象绑定,也不是将初始值拷贝给引用(初始化变量是把初始值拷贝给新建的对象中)

  • 对引用的所有操作都是对这个引用所绑定的对象的操作!
    如:

int ival = 1024;
int &refVal = ival;
refVal = 2;//即ival = 2;
int ii = refVal;//即 int ii = ival;
 
  • 最好用nullptr,比如int *p1=nullptr;这等价于int *p1=0;
  • 指针的值为0(控制之),则指针作为条件时,条件表达式取false,除此之外条件表达式都取true
  • 要理解一个变量(对象)的类型到底是什么,最简单的办法就是从右往左阅读这个变量的定义,离变量名最近的符号对变量的类型有最直接的影响
  • 一个对象去初始化另外一个对象,这两个对象是否有const修饰都可,比如:(拷贝一个对象的值是不会改变被拷贝的对象的)
int i=42;
const int ci=i;
int j=ci;

以上三行都正确。

  • 多文件使用相同const变量,就对这个const变量不管声明还是定义,都在最前加一个extern,如:(如果想在多个文件之间共享const对象,必须在变量的定义之前添加extern关键字)
//file_1.cpp定义并初始化一个常量,该常量能被其他文件访问
extern const int bufSize=fcn();
//file_1.h
extern const int bufSize;
//与file_1.cpp中定义的bufSize是同一个
  • 定义非const的引用不可绑定(指向)一个const对象,但const的引用可以绑定到非const对象上。
  • int i=42;const int &r2=i;此意是指不可以通过r2这个引用来修改i的值
  • 指针是对象,引用不是对象

关于const指针和引用,通过以下几点可以区分:

  • 关于const引用
const int ci=1024;
const int &ri=ci;//正确,引用和其绑定的对象都是const型
ri=42;//错误,const型对象不可变值
int &r2=ci;//非const型引用不可绑定到一个const型对象上!
int i=42;
const int &r1=i;//const型引用可以绑定到非const型对象(注意类型匹配)
const int &r2=42;//const型引用可以被赋值常量(字面值)
const int &r3=r1*2;//对,r3是const型引用,和r1类型一样的
int &r4=r1*2;//错误,r4是非const型引用,不可绑定到const型对象(通过r1这个const型引用)

//刷新,所有定义失效。
int i=42;
int &r1=i;//这两行都没问题,懂得都懂
const int &r2=i;//这个const型引用绑定到普通对象i,
				//但是不允许通过r2这个const型引用来改变i的值
r1=0;//对的,相当于i=0;
r2=0;//这行错误,r2为一个const型引用,
	 //这里体现了不允许通过r2这个const型引用来改变i的值
  • 关于const指针
    • 注意说法,指向常量(const型对象)的指针如下第3行,这种指针不能用于改变其所指向的对象的值,并且可以存放常量对象的地址
const double pi=3.14;//定义一个const型对象,这个对象的值不可以被改变
double *ptr=π//ptr是一个非const型指针
const double *cptr=π//正确,cptr是指向常量的指针,指向一个双精度型常量(相当于cptr这个指向常量的指针存放常量对象pi的地址)
*cptr=42;//错误,因为cptr是指向常量的指针,这种指针不能用于改变其所指向的对象的值

double dval=3.14;//dval是个普通的双精度型对象,它的值可以被改变
cptr=&dval;//这行正确,但是不能通过cptr这个指向常量的指针来改变dval的值,仅可以存放dval的地址。
  • 所以说指向常量的指针可以指向常量/非常量的对象,指向常量的指针说明不能通过该指针来改变对象的值,而可以通过其他途径来改变对象的值
  • 所以说指向常量的指针/引用,指向(或绑定)了常量后,就不能通过指向常量的指针/引用来改变其所指(或绑)对象的值了
int errNumb=0;
int *const curErr=errNumb;//curErr是一个const指针(常量指针,注意,与指向常量的指针有所区分),指向非const对象errNumb
const double pi=3.14159;
const double *const pip=π//pip是指向常量(对象)的常量指针
*pip-2.74;//错误,pip是指向常量的常量指针,不可改变其所指的对象的值
if(*curErr)
{
	errorHandler();
	*curErr=0;//正确,curErr常量指针指向一个普通对象(int errNumb=0;),
			  //所以可以通过curErr这个常量指针来修改它所指向的普通对象的值
}
  • 好了,下面说明一下const指针(常量指针)
    常量指针必须初始化,也就是必须给它赋值一个对象的地址,初始化完成,这个常量指针存放的地址就不可再改变!
    *放在const前(如int *const curErr=errNumb)意味着不变的是指针本身的值,这个常量指针指向的对象如果不是const型,对象的值还是可以改变的(通过其他途径)!
    指向常量的常量指针不论是常量指针所指的对象值还是常量指针自己存储的地址,都是不可以被改变的!
    如果指向非常量(对象)的常量指针,那么可以通过*常量指针=...的方式改变非常量对象
  • 重要的一点,弄清楚上述的声明的含义,最好的办法是一行从右往左读。
  • 编译器以引用的对象的类型作为auto的类型
  • auto一般忽略掉顶层const,如果希望推断出的auto类型是一个顶层const,则需这么写:
const auto f=ci;//之前有一个const int ci=i;因auto忽略顶层const的特性,
//ci的推演类型是int,所以f的推演类型是const int
  • 类体后面(以struct形式定义的类的{}后)可以紧跟变量名以示对该(类)类型对象的定义。
  • 类定义体后分号忘写,会出现以下情况
    在这里插入图片描述
  • 类所在头文件的名字应与类的名字一样
  • 头文件的内容被修改后,相关(包含该头文件的)源文件必须重新编译以获取更新过的声明。
  • 预处理变量(比如#define 什么什么。。。)无视C++中关于作用域的规则
  • 预处理变量名必须大写,而且整个程序中的预处理变量包括头文件保护符(#ifdef、#ifndef、#endif、#define等)必须唯一,并且每个头文件都加上这些头文件保护符
  • 基于头文件中类的名字来构建保护符的名字,如:
//在sales_data.h这个类头文件中
#ifndef SALES_DATA_H
#define SALES_DATA_H
#include<string>
struct Sales_data{
	std::string bookNo;
	unsigned units_sold = 0;
	double revenue = 0.0;
};
#endif

版权声明:本文为weixin_45910408原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。