C++_Chapter 2 对象与基本类型

Chapter 2 对象与基本类型

2-1 从初始化和赋值语句谈起

初始化和赋值语句是程序中最基本的操作,其功能是将某个值与一个对象关联起来

int x = 10; //初始化
x = 10;     //赋值语句

值:字面值(如上述10)、对象(变量、常量所表示的值)
标识符:变量、常量、引用—>(对象)
初始化基本操作:

1) 在内存中开辟空间(在栈上或者在堆上),用于保存值;
2) 在编译器中构造符号表,将标识符与相关的内存空间关联起来

值与对象都有类型!!(10也是有类型的)
初始化/赋值可能会涉及到类型转换

2-2 类型详述

类型是一个编译期概念,可执行文件中不存在类型的概念
C++是一个强类型语言,主要是在编译阶段与类型大量打交道
引入类型是为了更好的描述程序,防止误用
类型描述了四种信息:

#include <iostream>

int main()
 {
     int x = 10.5; // 4 byte --> 32 bit -->2^32
     char y = 'a';// 1 byte --> 4 bit --> 2^8

     std::cout << sizeof(x) <<'\n';
     std::cout << sizeof(char) <<'\n';
 }

1)类型存储所需要的尺寸,例如:int–>占多大的内存?;char–>占多大的内存?(在不同的编译环境下值可能不同)
2)取值空间(numeric_limits);
3)对齐信息(alignof)
4)类型可执行操作

基本(内建)类型:C++语言中所支持的类型

数值类型

·字符类型(char,wchar_t,char16_t,char32_t)
char是8位的,能表示256种字符,ASCII字符;
UTF-8编码???
wchar_t是宽字符类型,wchar_t一般为16位/32位,所能表示的字符数量超过char;
char32_t、char16_t可以实现Unicode编码;
·整数类型:
带符号整数类型与无符号整数类型
带符号整数类型:int & unsigned int(unsigned int==unsigned):int有负有正,unsigned int无符号
short–2个字节;int–4个字节;long/long long–8个字节;
·浮点类型:
float, double, long double
double尺寸比float宽一倍;
·void—特殊类型,不返回参数
·复杂类型:由基本类型组合、变种所产生的类型,可能是标准库引入,或自定义类型

与类型相关的标准未定义部分

char是否有符号?与编译器相关::unsigned char/signed char
整数在内存中的保存形式:大端/小端::在两台机器上传输数据的时候会考虑(网络传输)
每种类型的大小(间接影响取值范围)C++11 中引入了固定尺寸的整数类型,如int32_t

字面值及其类型
整数字面值:20,024,0x14—int型
浮点数:1.3,1e8—double型
字符字面值:‘c’,‘\n’,‘\x4d’—char型
字符串字面值:“Hello”—char[6]型(H e l l o \0)
布尔字面值:true,false—bool型
指针字面值:nullptr—nullptr_t型

引入前缀或后缀可改变字面值类型
可自定义后缀修改类型,用于例如单位转换等(User-defined literals)

变量及其类型

变量声明:extern前缀

# include <iostream>

extern int g_x;

int main
{
	std::cout << g_x <<std::ednl;
}

变量初始化与赋值

初始化:在构造变量之初为其赋予的初始值

​ 缺省初始化:int x = 0;(全局变量赋予初始值,函数内部赋予随机值)

​ 直接/拷贝初始化:int x(10)—直接初始化(问题:与int x{10}有什么区别);int x = 10—拷贝初始化;

​ 其他初始化

extern int g_x = 6//(由声明变为定义,后面就无法重复定义)
(隐式)类型转换

赋值可能出现类型转换,例如:int x = 1.3

bool与整数之间的类型转换:bool x = 1(0为False,非0为True)

类型转换过程中可能会出现丢失信息,promote不会,但是反过来会

小心隐式类型转换!!

if(3)—True

无符号与带符号的作比较,都会转换为无符号的

例如:

int x = -1;
unsigned int y = 3;
std::cout << (x<y) << std::endl;

输出结果为0,是因为int会被转化为unsigned int,x也就会被转换为很大的数 2 32 − 1 2^{32}-1 2321,从而判断为False。

如何避免?

std::cmp_XXX

2-3 复合类型:从指针到引用

指针
int x = 42;
int* p = &x;//将p指向x
/*
int *p;//随机初始化,可能指向有效内存,也可能不是
int *p = 0;//一般用这种方式,但在直接输出(cout)运行的时候会报错
*/
int y = 56;
p = &y;

指针特点:指向不同的对象,具有相同的尺寸;

相关操作:&-取地址操作符;*-解引用操作符

nullptr—一个指针

int* p = nullptr;//nullptr类型为nullptr_t,表示空指针,类似C++中的NULL
int* p = nullptr;
if(p)
{

}
else
{

}
int x = 42;
int* p = &x;

p = p + 1;//移动的是指针所指向的位置,会增加四个字节
p = p - 1;//减少四个字节

如果不在同一个数组中,不要比较两个指针,容易出现问题

void*指针:void*可以转换为其他指针,也可由其他指针转换过来

支持判等操作

void fun(void* param)
{

}

int main{
	int* r = nullptr;
	fun(r);
}

指针的指针

指针 v.s. 对象

指针:对对象的间接引用,复制成本低,读写成本高

指针的问题:

​ 可以为空

​ 地址可能非法(如空对象或者缺省初始化后的变量);

引用
int x = 3;
int& ref = x;

int* ptr = &x;
*ptr;

&x
int& x;//引用

引用是对象的别名

int x = 3;
int& ref = x;

std::cout << x << '\n';
ref = ref + 1;
std::cout << ref << '\n';

引用不能绑定字面值,如int& ref = 3是非法的。

构造时绑定对象,但在生命周期内不能绑定其他对象。

不存在空引用,可能存在非法引用。

属于编译器概念,在底层还是通过指针实现

指针的引用

指针是对象,因此可以定义引用

int x = 3;
int* ptr = &x;

int*& ref = ptr;//按照从右到左的顺序去解析---引用指针对象,指针对象指向int变量

是否存在引用的引用?不可以!

2-4 常量类型与常量表达式

常量类型
int main()
{
	const int x = 4;
	std::cout << x << '\n';
}

常量是编译器概念,编译器利用常量来进行:

  1. 防止非法操作
  2. 优化程序逻辑
int main()
{
	const int x = 4;
	
    if(x = 3)//该行报错
	{
	
	}
}

如果对象不修改,尽量声明为常量。

常量指针
int* const ptr = &x; //ptr指针不能被修改,不能指向其他对象
const int* ptr = &x; //ptr指向x,但不能用ptr改变x的值,ptr可以改变指向的对象地址

分辨const与*的位置关系

常量引用

也可绑定变量

const int& ref = x;//主要用于函数形参
常量表达式
int x;
std::cin >> x;

const int y1 = x;
const int y2 = 3;

使用constexpr声明:constexpr int y2 = 3;

常量表达式指针constexpr const int*

2-5 类型别名与类型的自动推导

类型别名

可以为类型引入别名,从而引入特殊的含义或便于使用(如:size_t)

typedef int MyInt; //引入类型别名
// using MyInt = int;  使用using引入类型别名更好
// typedef char AyCharArr[4];
// using MyCharArr = char[4];

int main()
{
	MyInt x = 3;
}

类型别名/引用/指针关系

指针—>指针的类型别名为一个整体:

using IntPtr = int*;

int x = 3;
const IntPtr ptr = &x;//--->const修饰IntPtr整体,是在顶层的
const int* ptr = &x;//---->const修饰int,而非int*

​ 应将指针类型别名视为一个整体,在此基础上引入常量表示指针为常量的类型;

​ 不能通过类型别名构造引用的引用。

类型的自动推导
int main()
{
	int x = 3.5 + 15l;//15l是指15 long类型
    
    std::cout << x << '\n';
}

结果为18;

int main()
{
	auto x = 3.5 + 15l;//编译器确定变量类型,为类型的自动推导,auto自动推导后仍为强类型
    
    std::cout << x << '\n';
}

结果为18.5;

auto x;为非法语句,需要有初始化表达式

自动推导的几种常见形式
auto x  //最常用的形式,但会产生类型退化
	/*
	auto x = 6.5+13l;//--->x的类型会变为double
	*/
const auto 
constexpr auto //推导出的是常量/ 常量表达式类型
	/*
	const int x = 3;
	const auto y = x;//---auto会被替换为int
	*/    
auto& // 推导出引用类型,避免类型退化
	/*
	const int x = 3;
	auto y = x;//--->y的类型会变为int
	auto& y = x;//--->y的类型会变为const int
	*/
    /*
    int x[3] = {1,2,3};
    auto x1 = x;//--->x1不会是数组,而会被退化为指针
    */
decltype(exp) //返回exp 表达式的类型(左值加引用)
	/*
	auto x = 3.5+15l;
	decltype(3.5+15l) x = 3.5+15l;//不产生类型退化
	*/
    /*
    表达式为左值,会加一个引用
    int* ptr = &x;
    ptr--->int*
    *ptr--->int
    decltype(*ptr)--->int&
    
    int x = 3;
    
    decltype(x)--->int
    */
decltype(val) //返回val 的类型
    /*
    变量名称会被直接推导为变量的类型
    std::cout << std::is_name_v<decltype(3.5+15l),double> << std::endl;
    */
decltype(auto) //从c++14 开始支持,简化decltype 使用
    /*
    auto x = 3.5+15l;
    decltypr(3.5+15l) x = 3.5+15l;
    decltype(auto) x = 3.5+15l;
    */
concept auto //从C++20 开始支持,表示一系列类型( std::integral auto x = 3; )
    /*
    # include <concepts>
    
    std::integral auto y = 3;
    std::cout << std::is_same_v<decltype(y),int> << std::endl;//结果为1
    
    std::integral auto y = 3.5;
    std::cout << std::is_same_v<decltype(y),int> << std::endl;//结果为0
    */

2-6 域与对象的生命周期

域(scope) 表示了程序中的一部分,其中的名称有唯一的含义

全局域( global scope ):程序最外围的域,其中定义的是全局对象

块域( block scope ),使用大括号所限定的域,其中定义的是局部对象

还存在其它的域:类域,名字空间域……

域可以嵌套,嵌套域中定义的名称可以隐藏外部域中定义的名称

对象的生命周期起始于被初始化的时刻,终止于被销毁的时刻

通常来说

​ – 全局对象的生命周期是整个程序的运行期间
​ – 局部对象生命周期起源于对象的初始化位置,终止于所在域被执行完成

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值