c++ primer(第五版)笔记 第二章(4)const, decltype, auto

#ifndef LESSON_2_4_H
#define LESSON_2_4_H
#include <iostream>

extern const int ciExt;

inline void print_ciExt()
{
	std::cout << ciExt << std::endl;
}

#endif // !LESSON_2_4_H

#include "lesson_2_4.h"
#include<typeinfo>

extern const int ciExt = 4;

void auto_test();
void practice_2_26();
void practice_2_27();
void practice_2_28();
void practice_2_29();
void const_test();
void constexpr_test();
void alias_test();
void decltype_test();

struct Foo{};	//注意分号

int main()
{
	//通过 const 关键字将变量定义成一个常量,而且以后不能再改变,所以 const 对象必须初始化,只能进行不改变其内容的操作
	//const 对象默认仅在文件内有效,如果需要多文件共享,需要在声明和定义时,使用 extern 关键字(在函数中进行该操作会报错)
	print_ciExt();	//4	头文件中 ciExt 和本文件中的 ciExt 是同一个对象
	practice_2_26();
	practice_2_27();
	practice_2_28();
	practice_2_29();
	const_test();
	constexpr_test();
	alias_test();
	auto_test();
	decltype_test();
	return 0;
}

void practice_2_26()
{
	//const int buf;	//Error	const object must be initialized if not extern
	int cnt = 0;
	const int sz = cnt;
	++cnt;
	//++sz;	//Error	cannot assign to a variable that is const
}

void practice_2_27()
{
	//int i = -1, &r = 0;	//'initializing' : cannot convert from 'int' to 'int &'
	const int i = -1, &r = 0;
	const int i2 = i;
	const int *p1 = &i2;
	//int *const p2 = &i2;//'initializing' : cannot convert from 'const int*' to 'int *const'
	const int *const p3 = &i2;
}

void practice_2_28()
{
	//int i, *const cp; i整型,cp 指向int的 const 指针,必须初始化
	//int *p1, *const p2; p1 整型指针,p2 指向int的 const 指针,必须初始化
	//const int ic, &r = ic; ic 常量,必须初始化, r 绑定整型常量 ic
	//const int *const p3; p3 是一个指向整型常量的常量指针,必须初始化
	const int *p; //p指向整型常量
}

void practice_2_29()
{
	//i = ic; const int 不能转换为 int
	//p1 = p3; const int* const 不能转换为 int *
	//p1 = &ic; const int* 不能赋值给 int *
	//p3 = &ic; p3是个常量,不能改变值
	//p2 = p1; p2是个常量,不能改变值
	//ic = *p3; ic是个常量,不能改变值
}

void const_test()
{
	//const 的引用(reference to const)
	//引用类型和所引用对象的类型不一致的特例之一:
	//在初始化常量引用时,允许用任意表达式作为初始值,只要能转换成引用的类型即可,比如非常量的对象,字面值,表达式
	double dval = 3.14;
	const int &ri = dval;
	//要保证 ri 所能执行的整数运算,上述代码通过编译器变为
	//double dval = 3.14;
	//const int temp = dval;
	//const int &ri = temp;
	//如果 ri 不是一个 const, 则通过 ri 应该可以改变所引用的对象 dval,但实际上 ri 绑定到一个临时量对象上,这种引用显然是无意义的,c++ 就把这种行为归为非法

	//指向常量的指针(pointer to const)
	//指针类型和所指向对象的类型不一致的特例之一:
	//允许令一个指向常量的指针指向一个非常量对象
	//所谓的指向常量的指针和引用,不过是指针和引用觉得自己指向常量,自觉不去改变,但所指向的对象可以通过其他途径改变值

	//执行对象拷贝时,顶层 const 不受影响,但必须有相同的底层 const 资格
	const int v2 = 0;
	int v1 = v2, *p1 = &v1, &r1 = v1;
	const int *p2 = &v2, *const p3 = &v2, &r2 = v2;

	r1 = v2;	//v2的顶层 const 被忽略
	//p1 = p2;	//p2 具有底层 const, p1不具备
	p2 = p1;
	//p1 = p3; p3 的顶层 const 被忽略,但p1 不具备底层 const 
	p2 = p3;//p3 的顶层 const 被忽略,并且和 p2 具备底层 const 
}

void constexpr_test()
{
	//常量表达式(const expression),值不会改变并且在编译过程就能得到计算结果的表达式
	//c++11 规定,允许将变量声明为 constexpr 类型以便由编译器来检验变量的值是否是一个常量表达式
	//字面值类型(literal type),算术类型,指针,引用
	//constexpr 的指针初始值必须为 nullptr 或者 0 或者存储在固定地址(定义于函数体外的对象)中的对象
	//constexpr 限定符仅对指针有效,对指向对象无关
	constexpr int *p = nullptr;	//指向整数的常量指针
	constexpr const int *p = nullptr;	//指向整数常量的常量指针
}

void alias_test()
{
	using pstring = char*;	//c++11
	typedef char * pstring1;//pstring类型相同

	const pstring cstr = 0;	//指向 char 的常量指针
	const pstring1 *ps = 0;//指针,指向一个指向char的常量指针
}

void auto_test()
{
	//c++11 引入 auto 类型说明符,让编译器去分析表达式类型
	//定义 auto 引用时,顶层 const 保留,其他类型只保留底层 const
	//2.35
	const int i = 42;
	std::cout << "type" << " i " << typeid(i).name() << std::endl;
	auto j = i;	//int
	std::cout << "type" << " j " << typeid(i).name() << std::endl;

	const auto &k = i;	//const int&
	std::cout << "type" << " i " << typeid(k).name() << std::endl;

	auto *p = &i;	//const int*
	std::cout << "type" << " i " << typeid(p).name() << std::endl;

	const auto j2 = i; //const int
	std::cout << "type" << " i " << typeid(j2).name() << std::endl;

	const auto &k2 = i;	//const int 
	std::cout << "type" << " i " << typeid(k2).name() << std::endl;
}
void decltype_test()
{
	//decltype返回变量和表达式的类型,包括 const 和 引用
	const int i = 0, &r = i;
	decltype(i) x = 0;	//x const int
	decltype(r) y = 0;	//y const int&
	//decltype(r) z;	//z const int& 必须初始化

	//如果表达式是一个解引用操作,decltype 返回引用类型
	int j = 0, *p = &j, &r1 = j;
	decltype(r1 + 0) h;	//a int,r1 + 0的结果是 int
	//decltype(*p) k;	//b int& 必须初始化

	//如果为变量增加一层括号,将得到引用
	decltype(j) l;	//	c int
	decltype((j)) m = j ;// int &,必须初始化
	
	//2.36
	int a = 3, b = 4;
	decltype(a) c = a;	//	c int
	decltype((b)) d = a;	//	d int&, (b) 不被视为变量,而是一个表达式
	++c;	//a = 3, b = 4, c = 4, d = 3
	std::cout << a << b << c << d << std::endl;
	++d;	//a = 4, b = 4, c = 4, d = 4
	std:: cout << a << b << c << d << std::endl;

	//2.37
	//赋值是一类产生引用的表达式,其引用的类型为左值的类型
	decltype(a = b) e = a;	//e int &
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章