#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 = ⁣ const int* 不能賦值給 int *
//p3 = ⁣ 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 &
}