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 &
}


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