程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> Bill學C++ 第一季之const 詳解

Bill學C++ 第一季之const 詳解

編輯:C++入門知識

Bill學C++ 第一季之const 詳解


零、文章來由

打算將基礎知識在看書的同時系統的整理一下,方便大家也方便自己。整理的知識盡量參照書本知識,比網上獲取的資料有更高的可信度。

一、從 文字常量和常變量 開始

1、文字常量

程序中的特殊標識符表達式,由於同時滿足:
(1)不可尋址(放在代碼區)
(2)值不可變
所以可視為文字常量。他們是 靜態數組名、枚舉變量、全局(靜態變量)首地址、#define定義的常量

整型文字常量:
(1)前加0表示 八進制
(2)前加0x表示 十六進制
(3)後加L(推薦)或l,表示long類型
(4)後加U(或u)表示無符號數

eg.1024UL

2、常變量Const

同其他變量一樣被分配空間,可尋址。

const是在高級語言的語義層面上定義的,是編譯器在編譯期做語法檢測來保證,但是運行時,const變量不是在只讀內存中,而是和一般變量一樣放在數據區,所以一樣可以對其進行修改。

所以:常變量是一種加了特殊限制的變量,理解成“只讀”變量

即使是const修飾,也是可以修改的

#include 
using namespace std;

void ShowValue(const int &i) {
    cout<

3、常變量替換

如果常變量有初始化賦初值,那編譯器將該常變量在其他地方替換成文字常量
但是如果開始不初始化就會錯誤

如:

void DefineArray(const int n){
     int B[n]={}; //error,數組大小在編譯期確定
}

int main(){
     const int m=5;
     int A[m]={}; //ok
}

4、文字常量和常變量尋址

int &r=5; //error,無法尋址文字常量,無法建立引用

const int &r=5; //ok,在數據區開辟一個值為5的無名整數量,然後將引用r與這個整形兩綁定

二、const用法

1、const的位置

int const *p; //指向常量的指針(即常指針,const修飾的是int),指向的對象是const型,不可以修改,但是指針p的指向可以修改
int *const p; //指針常量(const修飾的是int*),指針變量p是const型,它的指向不可修改,但是指向的對象可以修改

const和數據類型結合在一起 —>“常類型”。(看成一個整體)

修飾類型時,既可以放在放前面,也可以放在後面;用常類型聲明 or 定義變量,const只出現在變量前

const和被修飾類型間不能有其他標識符存在。

引用本身可以理解成一個指針常量

故在引用前使用const沒有意義

int & const r4=i; //const是多余的,編譯器warning後忽略const存在

const配合二重指針,此例子中const在不同位置,結果不同

#include 
using namespace std;

int main() 
{
    int const **p1; //不是指針常量,指向 int count*(“int const*”是一個 指向整型常量的指針)
    int *const *p2; //不是指針常量,但所指的變量是指針常量(int *const,即指向整型的指針常量,指向不能修改)

    int i=5;
    int j=6;

    const int *ptr1=&i;
    int *const ptr2=&j;

    p1=&ptr1;
    p2=&ptr2;

    cout<<**p1<

輸出:
5
6

上述p1和p2 賦值有講究,如果 p1=&ptr2 或 p2=ptr1 就會編譯錯誤

2、const修飾某個類 —> 常對象 和 常函數

const修飾對象–>常對象
const修飾成員函數—>常函數

在常函數中,不允許對任何成員變量進行修改

通過常對象,只能調用該對象的常函數

#include 
using namespace std;

class A
{
    int num;
public:
    A() {num=5;}
    void disp();
    void disp() const;
    void set(int n) {num=n;}

};

void A::disp() const {
    cout<

以上注意: (1)如果常函數聲明和定義分開,都需要加const,否則編譯錯誤

只有類的非靜態成員函數可以被聲明為常函數

(2)如果一個類的兩個成員函數,返回值、函數名、參數列表完全相同,其中之一是const,則重載。因為 常成員函數的參數傳入this指針是const Class*類型的,參數不同,導致函數簽名不同。

非只讀對象(如a1)調用某個函數(如 disp()),先找非const版本,如果沒有,再調用const版本。而常對象,只能調用類中定義的常函數,否則編譯器報錯。

如果一個非const對象(如a1)調用函數,同時有const和非const版本的函數,我們希望其調用const函數。就必須建立該對象的常引用,或指向該對象的常指針來達到目的。如: (const A&)a1.disp(); 或 (const A *)&a1->disp();

(3)常對象創建後,其數據成員不允許在修改。所以顯示構造函數來初始化該對象非常重要。

常對象,全體成員數據成員都是常量看待。 類對象的非靜態常量成員必須在構造函數中初始化,且只能借助初始化列表進行。

3、const修飾函數參數+函數返回值

#include 
using namespace std;

void disp1(const int &ri){
    cout<

注意:
(1)const修飾參數,主要作用是被引用對象被指向對象,如果只是形參,就沒有多少意義。如:void disp2(const int i),這裡的i在函數中改不改變,加不加const沒什麼影響。

不但如此,同時定義一個相似的用const修飾參數和不用const修飾參數的函數,會引起重定義錯誤。比如:任何整型表達式的值,都可以傳給int型參變量,也可以傳給const int型參變量,故不重載。

(2)當返回值是一個普通數據,而非引用,const修飾也沒多少意義。因為函數返回值是一個非左值,本來就不能改變其值。故其上 const int disp3(const int& ri),對返回值修飾然並卵。

(3)如果返回值為引用,用const修飾可以阻止對被引用對象修改,disp5(n)=6;是錯誤的

(4)常見的對const的誤解。

誤解一:用const修改的變量值一定是不能改變的。const修飾的變量可通過指針可間接修改。

如:

const int j=5;
void *p=(void *)&j;
int *ptr=(int *)p;
(*ptr)++;

誤解二:常引用或常指針,只能指向常變量,這是一個極大的誤解。常引用或者常指針只能說明不能通過該引用(或者該指針)去修改被引用的對象,至於被引用對象原來是什麼性質是無法由常引用(常指針)決定的。

三、const_cast 的用法

1、作用

const_cast 是 C++ 運算符,作用是去除符合類型中的const或者volatile

當大量使用const_cast是不明智的,只能說程序存在設計缺陷。使用方法見下例:

void constTest(){
    int i;
    cout<<"please input a integer:";
    cin>>i;
    const int a=i;
    int& r=const_cast(a);//若寫成int& r=a;則發生編譯錯誤
    ++r;
    cout<

輸入:
5

輸出:
6

總結:
(1)const_cast運算符的語法形式是const_cast< type> (expression)。 括號不可省略

(2)const_cast只能去除目標的const或者volatile屬性,不能進行不同類型的轉換。只能將 const type* 轉換為 type*,或者 const type & 轉換為 type &。
如下轉換就是錯誤的:

cons tint A={1,2,3}; 
char* p=const_cast< char*>(A); //不能由const int[]轉換為char* 

(3)一個變量被定義為只讀變量(常變量),那麼它永遠是常變量。cosnt_cast取消的是間接引用時的改寫限制,而不能改變變量本身的const屬性。 如下就是錯誤的:

int j = const_cast< int> (i);

(4)利用傳統的C語言中的強制類型轉換也可以將 const type* 類型轉換為 type* 類型,或者將 const type& 轉換為 type& 類型。但是使用 const_cast 會更好一些,因為 const_cast 寫法復雜(提醒程序猿不要輕易轉換),轉換能力較弱,目的明確,不易出錯,易查bug;而C風格的強制類型轉換能力太強,風險較大。


參考資料

[1]陳剛.C++高級進階教程[M].武漢:武漢大學出版社,2008.

   

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved