C++primer第二章2.4節對于const限定符相關內容進行詳解

?const限定符

  • const對象一旦創建后其數值就不會被再次改變,因此const對象必須初始化。
  • const對象只在文件中有效
  • 在不同的文件中使用不同的const來定義不同的常量,那么每個文件定義的變量只會在自己所屬的文件中有效。如果想讓多個文件共享同一個const變量,那么使用關鍵字extern即可

const的引用

把引用綁定到const對象上,就像綁定到其他對象上一樣,稱之為對于常量的引用。和普通信用不同,對于常量的引用不能被用于修改它所綁定的對象。

const int ci = 1024;
const int &r1 = ci;//正確,引用及其對應的對象都是常量
r1 = 42;          //錯誤,r1是對于常量的引用
int &r2 = ci;     //錯誤,試圖讓一個非常量去引用一個常量對象  
  • 因為不允許直接為ci賦值,當然也不可以通過引用去改變ci,因此,對于r2的初始化是錯誤的,假設初始化合法,就可以通過r2來改變他引用的對象的數值,這顯然是不正確的。

初始化和對const的引用

  • 引用的類型必須和其所引用對象的類型是一致的,但是有兩個例外。1,初始化常量引用時候允許用任意表達式來作為初始化的數值,只要該表達式結果可以轉化為引用的類型即可。尤其,允許一個常量引用綁定非常量的對象、字面值甚至是一個一般表達式。

    int i = 42;const int &r1 = i; //允許將const int& 綁定到一個普通int對象上const int &r2 = 42;//r2是一個常量的引用const int &r3 = r1 * 2;//r3是一個常量的引用int &r4 = r1 * 2;  //錯誤,r4是一個普通的非常量的引用

對const引用可能引用一個并非const的對象

  • 常量的引用僅僅對于可以引用可以參與的操作進行了限定,對于引用的對象的本身是不是一個常量未做限定。因為對象也可能是一個非常量,所以可以通過其他途徑來改變它的值。

    int i = 42;int &r1 = i; //引用r1綁定對象iconst int &r2 = i;//r2也綁定對象i,但是不允許通過r2來修改i的數值r1 = 0; //r1并非常量,i的數值修改為0r2 = 0; //錯誤,r2是一個常量的引用,因此不可以修改引用的元素的數值

指針和const

  • 與引用一樣,可以另指針指向常量或者非常量。類似于常量的引用,指向常量的指針不能用于改變其所指對象的數值
  • 要想存放常量對象的地址,只能指向常量的指針。
    const double pi = 3.141592653;   //pi是個常量,它的值不能改變double *ptr = π //錯誤,ptr是一個普通的指針const double *cptr = π //正確,cptr可以指向一個雙精度的常量*cptr = 43;//錯誤,不能給*cptr賦值
  • 指針的類型必須和所指對象類型一致,但是有兩個例外:1,允許令一個指向常量的指針指向一個非常量的對象。
double dval = 3.14;//dval是一個雙精度的浮點數,它的數值可以改變
cptr = &dval; //正確,但是不能通過cptr來改變dval的數值

const指針

  • 指針是對象而引用不是,因此就像其他對象類型一樣,允許把指針本身定位常量。常量指針必須初始化,而且一旦初始化,它的值(存放在指針中的那個地址)就不可以再改變了。

  • 把*放在const關鍵字之前用來說明指針是一個常量,即不變的是指指針本身的數值而不是指向的那個值

    int errNum = 0;int *const curErr = &errNum; //curErr一直指向errNumconst double pi = 3.14158;const double *const pip = π //pip是一個指向常量對象的常量指針
  • 遵循從右往左讀的思想
  • 離curErr最近的符號是const,意味著curErr本身是一個常量對象,對象的類型由聲明符的其余部分決定。聲明符的下一個符號是*,意思是curErr是一個常量指針。同理,pip是一個常量指針,指向的對象是一個雙精度浮點類型的常量。
  • 指針本身是一個常量并不意味著不能通過指針修改其所指向的數值,能否這樣做完全依賴于所指向的對象的類型。例如,如果pip是一個指向常量的常量指針,不論是pip所指的對象值還是pip自己存儲的那個地址都不能改變。如果,curErr指向的是一個一般的非常量整數,那么完全可以用curErr來修改errNum的數值。

頂層const

  • 指針本身是一個對象,它又可以指向另外一個對象,因此,指針本身是不是常量以及指針所指的是不是一個常量,是兩個相互獨立的問題。用名詞頂層const表示指針本身是一個常量;而使用名詞底層const來表示指針所指的對象是一個常量。
  • 頂層的const可以表示任意的對象是常量,這一點適用于任何數據類型,如算數類型、類、指針等。底層const則與指針和引用等符合類型的基本類型部分相關。
  • 比較特殊的是,指針類型既可以是頂層const也可以是底層const,這一點和其他類型相比區別比較明顯。
    int i = 0;int *const p1 = &i; //不可以改變p1的數值,這是一個頂層的constconst int ci = 42;  //不可以改變ci的數值,這是一個頂層的constconst int *p2 = &ci; //可以改變p2的數值,這是一個底層的constconst int *const p3 = p2; //靠右邊的是頂層const,靠左邊的是底層的constconst int &r = ci; //用于聲明的const都是底層const
  • 底層const限制不可以忽視。執行對象的拷貝操作的時候,拷入和烤出的對象具有相同的底層const資格,或者兩個對象的數據類型之間能夠相互轉化,一般來說非常量可以轉化為常量,反之不可以。

constexper和常量表達式

  • 常量表達式是指不會改變并且在編譯的過程中能得到編譯結果的表達式。顯然,字面值屬于常量表達式,用常量表達式初始化的const對象也是常量表達式。
  • 一個對象或者表達式是不是常量表達式是由它的數據類型和初始值共同決定的。
    const int max_files = 20; //max_files是常量表達式const int limit = max_files + 1; //limit是常量表達式int staff_size = 27;//staff_size不是常量表達式const int sz = get_size();//sz不是常量表達式
  • staff_size的初始值是一個字面值常量,但是由于他的數據類型只是一個普通的int而不是const int,所以他不屬于常量表達式。
  • sz本身是一個常量,但是他的具體值直到運行的時候才可以獲取到,因此也不是常量表達式。

constexpr變量

  • C++11允許將變量聲明為constexpr類型,從而使得編譯器來驗證變量的數值是否是一個常量的表達式。
  • 聲明為constexpr的變量一定是一個常量,而且需要用常量表達式來初始化。
    constexpr int mf = 20; //20是常量表達式constexpr int limit = mf + 1 ;// limit是常量表達式constexpr int sz = size();// 只有當size是一個constexpr函數的時候,才是一條正確的聲明語句

字面值類型

  • 常量表達式的值需要在編譯的時候就得到計算,因此對聲明constexpr時用到的類型必須有所限制。因為這些類型一般比較簡單,值也比較明顯,將其稱之為字面值類型。
  • 算數類型、引用和指針都是屬于字面值類型。自定義的類型、IO庫、string則不屬于字面值類型,即不可以定義為constexpr。
  • 指針和引用可以被定義為constexpr類型,但是他們的初始值會受到嚴格的限制,constexpr指針的初始值必須是nullptr或者是0,或者是存儲于某個固定地址中的對象。
  • 先前指出函數體內部定義的變量一般來說不會存在到固定的地址中,因此constexpr指針不可以指向這種變量。相反,因為存儲于函數體外的對象其固定的地址不變,因此可以用于初始化constexpr指針。
  • 其中,允許函數定義一類有效范圍超出函數本身的變量,這類變量和定義在函數體之外的變量一樣也有固定的地址,因此也可以用于對于constexpr指針的初始化。

指針和constexpr

  • 在constexpr聲明中定義了一個指針,限定符號constexpr僅僅對于指針有效,而對于指針所指向的對象本身無效。
    const int *p = nullptr;//p是一個指向整型常量的指針constexpr int *q = nullptr;//q是一個指向整數的常量指針
  • 與其他常量指針相類似,constexpr指針既可以指向一個常量指針,也可以指向一個非常量
const int *np = nullptr;//np是一個指向整數的常量指針,其值為空
int j = 0;
constexpr int i = 42;//i的類型是整型常量
//i和j必須定義在函數體之外constexpr const int *p = &i;//p是常量指針,指向整型常量iconstexpr int *p1 = &j;

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/447063.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/447063.shtml
英文地址,請注明出處:http://en.pswp.cn/news/447063.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

二分法的常見問題

mid(leftright)/2; mid (high - low) / 2 low; 這樣寫可以防止left right溢出 ,不過數足夠大是時候該溢還是溢 為什么要取右邊中間數呢?這是因為在區間里 只有 2 個元素的時候,把[left…right]劃分成[left…mid - 1]和[mid…right]這兩個區間&#x…

演示IPFS的一個完整的流程以及針對部分概念的詳解

整體的流程 1,創建ipfs節點 通過ipfs init在本地計算機建立一個IPFS節點本文有些命令已經執行過了,就沒有重新初始化。部分圖片拷貝自先前文檔,具體信息應以實物為準 $ ipfs init initializing IPFS node at /Users/CHY/.ipfs generating 2…

c++ 算法的時間復雜度

一般ACM或者筆試題的時間限制是1秒或2秒。 在這種情況下&#xff0c;C代碼中的操作次數控制在 10^7為最佳。 下面給出在不同數據范國下&#xff0c;代碼的時間復雜度和算法該如何選擇&#xff1a; 1.n≤ 30,指數級別&#xff0c;dis剪枝&#xff0c;狀態壓縮dp 2.n < 100 &g…

簡單工廠模式實現計算器

#include <iostream> #include <vector> #include <string> #include <iostream> #include <map> using namespace std; #define __THROW_ZERO do {cerr << "The dividend is 0" << endl; exit(1);}while(0);/* 簡單工廠處…

TDengine安裝教程

TDengine安裝教程 前言 TDengine的安裝十分簡單&#xff0c;可以有以下三種安裝方式&#xff0c;源碼安裝、通過Docker容器進行安裝、通過安裝包進行安裝。但是使用源碼安裝較為復雜&#xff0c;通過docker的方式最為簡單&#xff0c;但是需要一定docker相關的知識&#xff0…

C++中size_t的學習

size_t的定義 size_t是一種數據相關的無符號類型&#xff0c;它被設計得足夠大以便能夠存儲內存中任意對象的大小。設計 size_t 就是為了適應多個平臺&#xff0c;size_t等效于unsigned short int 或者 unsigned long int 類型&#xff0c;這個過程是動態匹配的。在需要通過數…

策略模式解決商店打折問題

#include <bits/stdc.h> using namespace std; /*策略模式解決商店打折問題*/class Cashsuper { private:/* data */ public:virtual double addcash(double cash) 0;double Getresult(double money){return addcash(money);} };class Cashnormal : public Cashsuper {p…

android 軟件首次運行時引導頁左右滑動效果

很多手機軟件在安裝后首次運行都會進入到引導頁面&#xff0c;再次運行時會進入到主頁面。 多了不說了&#xff0c;先看效果圖&#xff1a; 代碼如下&#xff1a; main.xml <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:an…

C++中size_type類型詳解

介紹 是和string類類型和vector類類型定義相關的類型&#xff0c;用以保存任意string對象或vector對象的長度&#xff0c;標準庫類型將size_type定義為unsigned類型string抽象意義是字符串&#xff0c; size&#xff08;&#xff09;的抽象意義是字符串的尺寸&#xff0c; str…

單一職責原則 實現貪吃蛇代碼的封裝

單一職責原則(SRP),就一個類而言&#xff0c;應該僅有一個引起它 變化的原因。 一個c語言的貪吃蛇代碼 如何使用單一職責原則封裝成c面向對象呢 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #include<stdlib.h> #include <wi…

android ProgressBar實現掃描SD卡文件 + SimpleAdapter綁定ListView

代碼 activity_main.xml <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"android:layout_width"match_parent"android:layout_height"match_parent"to…

C++標準庫函數begin和end函數

主要的目的 為了讓指針更加簡單、安全&#xff0c;引入了begin和end函數&#xff0c;這兩個函數和容器中兩個同名的成員函數類似。但是由于數組畢竟不是類類型&#xff0c;因此這兩個函數不是成員函數。正確的使用形式就是將數組作為他們的參數int ia[] {0,1,2,3,4,5,6,7,8,9…

dex分包之--------multidex包的配置使用

目錄&#xff1a;一、前言二、產生原因三、MultiDex的簡要原理四、MultiDex的使用 一、前言 首先說一下我遇到的情況&#xff0c;最近接手了一個項目是在已有的項目里進行更新添加一些功能&#xff0c;然后該項目導了N多的包&#xff0c;在我使用Android Studio的run”App”直…

C++ primer第六章函數的學習

介紹 首先介紹函數的定義和聲明&#xff0c;包括如何傳入參數以及函數如何返回結果。C語言允許使用重載函數&#xff0c;即幾個不同的函數可以使用向同一個名字。所以接下來介紹重載函數的方法&#xff0c;以及編譯器選擇如何從函數的若干重載的形式中選取一個與調用模板相互匹…

C語言指針作為函數參數 以及智能指針作為函數參數

總所周知指針作為函數參數傳遞的時候 傳遞的是指針的拷貝&#xff08;指針也是變量&#xff09; 這里提供四種指針的傳遞方法 改到實際的指針。 #include <stdio.h> #include <memory> #include <iostream> using namespace std; void test1(char **string)…

Android Studio打包和引用aar

一、簡介 Android 庫在結構上與 Android 應用模塊相同。它可以提供構建應用所需的一切內容&#xff0c;包括源代碼、資源文件和 Android 清單。不過&#xff0c;Android 庫將編譯到您可以用作 Android 應用模塊依賴項的 Android 歸檔 (AAR) 文件&#xff0c;而不是在設備上運行…

C++ primer第六章6.4函數的學習 之函數的重載

6.4 函數的重載 函數的名字相同但是形參的列表不同&#xff0c;將其稱之為重載函數 void print(const char *cp); void print(const int *beg,const int * end); void print(const int ia[],size_t size); 形如上面所展現的這樣&#xff0c;當調用這些函數的時候&#xff0c;…

C++有限狀態機的實現

//待完善 有限狀態機是一個很常用的技術&#xff0c;在流程控制和游戲AI中都比較實用&#xff0c;因為狀態機編程簡單又很符合直覺。與有限狀態機類似的是設計模式中的狀態模式。本文是參考《Programming Game AI by Example》 一、 記得最開始工作時候也接觸過有限狀態機&…

手勢希爾排序

void shell_sort(int *data, int length){int gap0;int i0,j0;for(gaplength/2;gap>1;gap/2){//組內插入排序for(igap;i<length;i){int temp data[i];for(ji-gap;j>0&&temp<data[j];jj-gap){data[jgap]data[j];}data[jgap]temp;}} }