當前位置:
首頁 > 知識 > const 注意事項(初始化,重載,參數和返回值)

const 注意事項(初始化,重載,參數和返回值)

1 const 類成員初始化

(a) 成員只有 const, 類似引用, 需要在初始列表進行初始化(特殊情況C+11特性, 如果是整數(char, short, int), 可以直接在聲明處賦值)。

(b) 成員既有 const 又有 static, 按照 static 初始化方式。

  1. #include <iostream>
  2. #include <stdio.h>
  3. using namespace std;
  4. class MyTest
  5. {
  6. public:
  7. MyTest():
  8. m_ConstString("My Test !!!")
  9. {
  10. }
  11. void printMyTest()
  12. {
  13. std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
  14. std::cout << "m_ConstString=" << m_ConstString << endl;
  15. std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
  16. }
  17. private:
  18. const int m_ConstVarInt = 100; // 成員只有 const, 特殊情況C+11特性, non-static data member initializers only available with -std=c++11 or -std=gnu++11
  19. const std::string m_ConstString; // 成員只有 const
  20. static const int mStaticConstVarInt; //成員既有 const 又有 static
  21. };
  22. const int MyTest::mStaticConstVarInt = 1000;
  23. int main()
  24. {
  25. MyTest test;
  26. test.printMyTest();
  27. return 0;
  28. }

程序運行結果:

  1. m_ConstVarInt=100
  2. m_ConstString=My Test !!!
  3. mStaticConstVarInt=1000

2. const 重載

類中函數只有 const 屬性不同, 可以進行函數重載(注意, 普通函數不可以)

  1. #include <iostream>
  2. #include <stdio.h>
  3. using namespace std;
  4. class MyTest
  5. {
  6. public:
  7. MyTest():
  8. m_ConstString("My Test !!!")
  9. {
  10. }
  11. void printMyTest()
  12. {
  13. std::cout << "printMyTest !!!!!" << endl;
  14. std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
  15. std::cout << "m_ConstString=" << m_ConstString << endl;
  16. std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
  17. }
  18. void printMyTest() const
  19. {
  20. std::cout << "printMyTest const !!!!!" << endl;
  21. std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
  22. std::cout << "m_ConstString=" << m_ConstString << endl;
  23. std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
  24. }
  25. private:
  26. const int m_ConstVarInt = 100; // 成員只有 const, 特殊情況C+11特性, non-static data member initializers only available with -std=c++11 or -std=gnu++11
  27. const std::string m_ConstString; // 成員只有 const
  28. static const int mStaticConstVarInt; // 成員既有 const 又有 static
  29. };
  30. const int MyTest::mStaticConstVarInt = 1000;
  31. int main()
  32. {
  33. const MyTest testConst;
  34. //訪問重載的const成員
  35. testConst.printMyTest();
  36. MyTest test;
  37. //訪問重載的非const成員
  38. test.printMyTest();
  39. return 0;
  40. }

程序運行結果:

  1. printMyTest const !!!!!
  2. m_ConstVarInt=100
  3. m_ConstString=My Test !!!
  4. mStaticConstVarInt=1000
  5. printMyTest !!!!!
  6. m_ConstVarInt=100
  7. m_ConstString=My Test !!!
  8. mStaticConstVarInt=1000

3 const 類對象

const 類對像只能訪問 const 成員

  1. #include <iostream>
  2. #include <stdio.h>
  3. using namespace std;
  4. class MyTest
  5. {
  6. public:
  7. MyTest():
  8. m_ConstString("My Test !!!")
  9. {
  10. }
  11. void printMyTest()
  12. {
  13. std::cout << "printMyTest !!!!!" << endl;
  14. std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
  15. std::cout << "m_ConstString=" << m_ConstString << endl;
  16. std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
  17. }
  18. void printMyTest() const
  19. {
  20. std::cout << "printMyTest const !!!!!" << endl;
  21. std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
  22. std::cout << "m_ConstString=" << m_ConstString << endl;
  23. std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
  24. }
  25. void printConstVarInt()
  26. {
  27. std::cout << "printConstVarInt !!!!!" << endl;
  28. std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
  29. }
  30. private:
  31. const int m_ConstVarInt = 100; // 成員只有 const, 特殊情況C+11特性, non-static data member initializers only available with -std=c++11 or -std=gnu++11
  32. const std::string m_ConstString; // 成員只有 const
  33. static const int mStaticConstVarInt; // 成員既有 const 又有 static
  34. };
  35. const int MyTest::mStaticConstVarInt = 1000;
  36. int main()
  37. {
  38. const MyTest testConst;
  39. // 可以訪問
  40. testConst.printMyTest();
  41. // 不可以訪問, 會報錯
  42. // testConst.printConstVarInt();
  43. return 0;
  44. }

程序運行結果:

  1. printMyTest const !!!!!
  2. m_ConstVarInt=100
  3. m_ConstString=My Test !!!
  4. mStaticConstVarInt=1000

4 const 函數改變成員變數

可以使用 mutable 在const 函數的內部改變成員變數

  1. #include <iostream>
  2. #include <stdio.h>
  3. using namespace std;
  4. class MyTest
  5. {
  6. public:
  7. MyTest():
  8. m_ConstString("My Test !!!")
  9. {
  10. }
  11. void printMyTest()
  12. {
  13. std::cout << "printMyTest !!!!!" << endl;
  14. std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
  15. std::cout << "m_ConstString=" << m_ConstString << endl;
  16. std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
  17. }
  18. void printMyTest() const
  19. {
  20. std::cout << "printMyTest const !!!!!" << endl;
  21. // 成員變數遞增
  22. m_VarInt++;
  23. std::cout << "m_VarInt=" << m_VarInt << endl;
  24. std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
  25. std::cout << "m_ConstString=" << m_ConstString << endl;
  26. std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
  27. }
  28. private:
  29. const int m_ConstVarInt = 100; // 成員只有 const, 特殊情況C+11特性, non-static data member initializers only available with -std=c++11 or -std=gnu++11
  30. const std::string m_ConstString; // 成員只有 const
  31. static const int mStaticConstVarInt; // 成員既有 const 又有 static
  32. mutable int m_VarInt; // 普通成員, mutable 可以在const成員函數裡面改變值
  33. };
  34. const int MyTest::mStaticConstVarInt = 1000;
  35. int main()
  36. {
  37. const MyTest testConst;
  38. // 第一次調用
  39. testConst.printMyTest();
  40. // 第二次調用
  41. testConst.printMyTest();
  42. return 0;
  43. }

程序運行結果:

  1. printMyTest const !!!!!
  2. m_varInt=1
  3. m_ConstVarInt=100
  4. m_ConstString=My Test !!!
  5. mStaticConstVarInt=1000
  6. printMyTest const !!!!!
  7. m_varInt=2
  8. m_ConstVarInt=100
  9. m_ConstString=My Test !!!
  10. mStaticConstVarInt=1000

5 const 返回值

為什麼有的函數的返回值為const?

對返回值使用const有可能提高一個函數的安全性和效率,否則還會出問題。

例如:

const rational operator*(const rational& lhs,

const rational& rhs);

很多程序員第一眼看到它會納悶:為什麼operator*的返回結果是一個const對象?因為如果不是這樣,用戶就可以做下面這樣的壞事:

rational a, b, c;

...

(a * b) = c; // 對a*b的結果賦值

我不知道為什麼有些程序員會想到對兩個數的運算結果直接賦值,但我卻知道:如果a,b和c是固定類型,這樣做顯然是不合法的。一個好的用戶自定義類型的特徵是,它會避免那種沒道理的與固定類型不兼容的行為。對我來說,對兩個數的運算結果賦值是非常沒道理的。聲明operator*的返回值為const可以防止這種情況,所以這樣做才是正確的。

(a) 案例1:非const 返回值, 導致的異常操作

(testOne + testTwo) = testThree

  1. #include <iostream>
  2. #include <stdio.h>
  3. using namespace std;
  4. class Test
  5. {
  6. public:
  7. Test(const int varInt = 100):
  8. m_VarInt(varInt)
  9. {
  10. }
  11. // 返回值沒有 const
  12. Test operator+(const Test& test)
  13. {
  14. Test tmpTest;
  15. tmpTest.m_VarInt = this->m_VarInt + test.getVarInt();
  16. return tmpTest;
  17. }
  18. int getVarInt()const
  19. {
  20. return m_VarInt;
  21. }
  22. private:
  23. int m_VarInt;
  24. };
  25. int main()
  26. {
  27. Test testOne(100);
  28. Test testTwo(200);
  29. Test testThree(0);
  30. //這種異常情況, 竟然可以賦值沒有編譯和運行報錯提示
  31. (testOne + testTwo) = testThree;
  32. return 0;
  33. }

(a) 案例2:const 返回值, 編譯報錯處理, 可以保證下述異常不會發生

(testOne + testTwo) = testThree

  1. #include <iostream>
  2. #include <stdio.h>
  3. using namespace std;
  4. class Test
  5. {
  6. public:
  7. Test(const int varInt = 100):
  8. m_VarInt(varInt)
  9. {
  10. }
  11. // 返回值加上 const
  12. const Test operator+(const Test& test)
  13. {
  14. Test tmpTest;
  15. tmpTest.m_VarInt = this->m_VarInt + test.getVarInt();
  16. return tmpTest;
  17. }
  18. int getVarInt()const
  19. {
  20. return m_VarInt;
  21. }
  22. private:
  23. int m_VarInt;
  24. };
  25. int main()
  26. {
  27. Test testOne(100);
  28. Test testTwo(200);
  29. Test testThree(0);
  30. //這種異常情況, 編譯編譯不能通過, 會報錯處理
  31. (testOne + testTwo) = testThree;
  32. return 0;
  33. }

6 const 參數

C++引用------( 臨時變數、引用參數和const引用 )

如果實參與引用參數不匹配,C++將生成臨時變數。如果引用參數是const,則編譯器在下面兩種情況下生成臨時變數:

實參類型是正確的,但不是左值

實參類型不正確,但可以轉換為正確的類型

左值參數是可被引用的數據對象,例如,變數、數組元素、結構成員、引用和被解除引用的指針都是左值,非左值包括字面常量和包含多項式的表達式。定義一個函數

  1. double refcube(const double& ra)
  2. {
  3. return ra*ra*ra;
  4. }
  5. double side = 3.0;
  6. double* pd = &side;
  7. double& rd = side;
  8. long edge = 5L;
  9. double lens[4]={2.3,3.4,4.5,6.7};
  10. double c1 = refcube(side); // ra 是side
  11. double c2 = refcube(lens[2]); // ra是lens[2]
  12. double c3 = refcube(rd); // ra 是 rd
  13. double c4 = refcube(*pd); // ra 是*pd
  14. double c5 = refcube(edge); // ra 是臨時變數
  15. double c6 = refcube(7.0); // ra 是臨時變數
  16. double c7 = refcube(side+10.0); // ra 是臨時變數

參數side lens[2] rd 和*pd都是有名稱的、double類型的數據對象,因此可以為其創建引用,而不需要臨時變數。但是edge雖然是變數,類型卻不正確,double引用不能指向long。另一方面,參數7.0和side+10.0的類型都正確,但沒有名稱,在這些情況下,編譯器都將生成一個臨時匿名變數,並讓ra指向它。這些臨時變數只在函數調用期間存在,伺候編譯器便可以任意將其刪除

那麼為什麼對於常量引用,這種行為是可行的,其他情況下卻不行呢?

  1. void swapr(int& a,int& b)
  2. {
  3. int temp;
  4. temp=a;
  5. a = b;
  6. b = temp;
  7. }

在早期的C++較寬鬆的規則下,執行下面的操作將發生什麼?

long a = 3,b = 5;

swapr(a,b);

這裡的類型不匹配,因此編譯器將創建兩個臨時的int變數,將他們初始化為3和5,然後交換臨時變數的內容,而a和b保持不變

簡而言之,如果接受引用參數的函數的意圖是修改作為參數傳遞的變數,則創建臨時變數將阻止這種意圖的實現,解決方法是,禁止創建臨時變數,現在的C++標準正是這樣做的、

現在來看refcube()函數,該函數的目的只是使用傳遞的值,而不是修改他們,因此臨時變數不會造成任何不利的影響。反而會使函數在可處理的參數種類方面更通用。因此,如果聲明將引用指定為const,C++將在必要時生成臨時變數、實際上,對於形參為const引用的C++函數,如果實參不匹配,則其行為類似於按值傳遞,為確保原始數據不被修改,將使用臨時變數來存儲值、

(PS:如果函數調用的參數不是左值或與相應的const引用參數的類型不匹配,則C++將創建類型正確的匿名變數,將函數調用的參數的值傳遞給該匿名變數,並讓參數來引用該變數)

應儘可能使用const

使用cosnt可以避免無意中修改數據的編程錯誤

使用const使函數能夠處理const和非const實參,否則將只能接受非const數據

使用const引用使函數能夠正確生成並使用臨時變數

const 注意事項(初始化,重載,參數和返回值)

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

mysql定時任務和存儲過程的小例子
程序員如何快速搭建個性化主頁

TAG:程序員小新人學習 |