博客 / 詳情

返回

Java中的final 和 C++中的final、const(C++中const關鍵字功能總結)

目錄
  • Java中final有三種主要用法:
  • C++中final只有兩種:
  • C++中const:
    • 修飾變量(基本類型變量、成員變量):
    • const與引用:
    • const與指針:"const在*前,數據不能改,const在*後,指針不能改"
    • const在函數中的應用:
    • const修飾對象:

Java中final有三種主要用法:

  1. 修飾變量:final變量是不可改變的,但它的值可以在運行時刻初始化,也可以在編譯時刻初始化,甚至可以放在構造函數中初始化,而不必在聲明的時候初始化,所以下面的語句均合法:

    final int i = 1; // 編譯時刻
    final int i2 = (int)(Math.Random() * 10); //運行時刻
    final int i3; //構造函數裏再初始化
    

    final經常和static一起用,這種用法類似C++的常量,在Java中很常見,比如 static final i = 10; 但這裏同樣也是允許運行時刻初始化的。

  2. 修飾類對象:而如果修飾類對象,並不表示這個對象不可更改,而是表示這個這個變量不可再賦成其它對象,這就比較像 C++的 Class const * p了(這樣表明這個指向該Class的指針p不能再指向其他對象,指針常量,但是該對象中的值是可以修改的(const Class *p常量指針,任何成員變量都不能修改))。

    final Value v = new Value(); 
    v = new Value(); //不允許! 
    v.some_method(); //允許
    
  3. 修飾方法:final修飾的方法是不能被重載的,類似於類中的private方法,所以private方法默認是final的;大致説就是變量不可修改(基本數據類型值不能修改,類類型引用不能修改),方法不可重載,類不可繼承,

C++中final只有兩種:

  1. 修飾類

  2. 修飾虛函數

C++中const:

C++中的const用處很多,包括常量聲明、變量修飾、常量引用、指針與const的組合、以及常量對象、成員函數。

修飾變量(基本類型變量、成員變量):

  • 修飾基本類型變量

    修飾變量也可以叫作常量的聲明,使用const關鍵字可以修飾變量,一旦初始化後就不能再修改其值。

    const int MAX = 123;
    const double PI = 3.14;
    const int x = 334;
    

    以上的MAX、PI、x將都不能再修改其值;

    const定義的常量和#define宏定義的常量的區別

    const常量有數據類型,define宏定義常量沒有,編譯器會對const常量可以進行數據類型的安全檢查,但是對於define宏定義,編譯器只是將其進行字符替換,這樣的字符替換很容易出錯。

    比如以下代碼,如果使用不加括號的宏定義,將不能正確計算(a+b)/5.0,而是變成計算a+(b/5.0)了。

    //define宏定義的做法
    #define a 2.0
    #define b 9.0
    #define c1 a+b   //不好的定義方法
    #define c2 ((a)+(b))  //推薦的定義方法
    void func1(void)
    {
        float d1 = c1/5.0;  //本意是想計算(a+b)/5.0,但字符替換使計算變成了a+b/5.0
        float d2 = c2/5.0;  //正確計算了((a)+(b))/5.0 = (a+b)/5.0
    }
    
    
    //推薦的const常量的做法
    const float a = 2.0;
    const float b = 9.0;
    const float c = a + b;
    void func2(void)
    {
        float d = c/5.0;  //正確計算了(a+b)/5.0
    }
    
  • 修飾成員變量:在類中,使用const修飾的成員變量只能在初始化列表中進行初始化,並且不能在構造函數中修改其值。

    class MyClass {
    public:
        const int x;
        MyClass(int value) : x(value) {} // 初始化const修飾的成員變量
    };
    

    這段代碼定義了一個類MyClass,其中有一個const修飾的整型成員變量x。在構造函數的初始化列表中對x進行初始化,且只能在初始化列表中初始化,不能在構造函數內部修改其值。

const與引用:

const引用可以綁定到臨時對象或字面量,延長其生命週期。

用這種方式聲明的引用,不能通過引用對目標變量的值進行修改,從而使引用的目標成為const,達到了引用的安全性。

const int& ref = 10; // 合法
// int& ref2 = 10;   // 非法:非常量引用不能綁定字面量
int x = 10;
const int& a = x;
x = 5;

const與指針:"const在*前,數據不能改,const在*後,指針不能改"

  • 常量指針:

    形式:const type* ptr(推薦) 或 type const* ptr

    這裏可以理解為 const修飾的是type類型的數據:(const type)* ptr 或 (type const)* ptr,也就是説不能通過ptr修改值,但ptr可以指向其他地址。

    int a = 10, b = 20;
    const int* ptr = &a;
    *ptr = 30; // 錯誤:不能修改指向的數據
    ptr = &b;  // 正確:可以改變指針指向
    

    "const在*前,數據不能改"

  • 指針常量:

    形式:type* const ptr

    這裏可以理解為const修飾的是ptr:也就是説ptr一旦初始化指向之後就不能指向其他地址,但可以通過指針修改所指向的數據。

    int a = 10, b = 20;
    int* const ptr = &a;
    *ptr = 30; // 正確:可以修改a的值
    ptr = &b;  // 錯誤:不能改變指針指向
    

    "const在*後,指針不能改"

  • 指向常量 的 常量指針:

    形式:const type* const ptrtype const* const ptr

    既不能修改指針指向,也不能通過指針修改數據。

    int a = 10, b = 20;
    const int* const ptr = &a;
    *ptr = 30; // 錯誤
    ptr = &b;  // 錯誤
    

const在函數中的應用:

  • const形參:避免函數內意外修改參數,常用於指針或引用傳參。

    void print(const int* arr, int size) {
        for (int i = 0; i < size; ++i)
            std::cout << arr[i] << " "; // 只讀訪問
    }
    
  • const成員函數:const修飾類成員函數,實際修飾該成員函數隱含的this指針,表明在該成員函數中不能對類的任何成員進行修改。

    class MyClass {
        int value;
    public:
        int getValue() const { return value; } // 不會修改對象狀態
    };
    
  • const返回值:也是用const來修飾返回的指針或引用,保護指針指向的內容或引用的內容不被修改,也常用於運算符重載。

    函數三種返回類型:返回值、返回引用(&)、返回指針(*);

    • 返回值:

      現在返回值使用const幾乎沒有意義,例如:

      const int ten(){
          return 10; //返回值是一個臨時對象
      }
      
      //在後續的賦值中
      const int x = ten();
      

      在c++11之後,臨時對象本來就不能被修改,所以 const int ten()int ten()本質上效果一樣。

    • 返回引用或者指針(這裏用引用舉例,指針一樣的道理):

      引用返回值不是重新創建一個對象,而是直接把函數內部(或外部某處)的對象引用返回給調用者;

      這樣將不會產生對象拷貝(性能高),調用者直接訪問的就是原對象。

      給引用加const可以保護原對象不被調用者修改,例如:

      class A {
      public:
      	int& getValue2(){
      		return m_value;
      	}
      	const int& getValue(){
      		return m_value;
      	}
      private:
      	int m_value = 10;
      };
      
      int main() {
      	A a;
      	a.getValue() = 100;   //不允許修改
      	a.getValue2() = 111;  //直接修改成員
      }
      

      getValue()將不允許修改成員變量m_value,而getValue2()將會直接修改成員變量m_value;

      一般get函數會被const修飾const int& getValue const(){return m_value}這樣函數內的成員變量也會被const修飾,不允許修改。

      在返回const引用要注意:返回對象的生命週期必須比函數長,例如:

      const int& backNum() {
      	int num = 1;
      	return num;    //錯誤:num會在函數結束後消失,這塊內存的位置也會給其他變量用
      }
      void otherFunc() {
      	int a = 100;
      	int b = 200;
      }
      int main() {
      
      	const int& c = backNum();
      	otherFunc();
      	cout << c << endl;
      }
      

      這樣的引用指向在程序複雜的時候會造成懸空引用,未定義行為等危險。

const修飾對象:

const修飾的對象,其成員變量都不能被修改。

class MyClass {
public:
    int x;
};

const MyClass obj; // 常量對象
// obj.x = 10; // 錯誤,常量對象的成員變量不能被修改
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.