const 注意事項(初始化,重載,參數和返回值)
1 const 類成員初始化
(a) 成員只有 const, 類似引用, 需要在初始列表進行初始化(特殊情況C+11特性, 如果是整數(char, short, int), 可以直接在聲明處賦值)。
(b) 成員既有 const 又有 static, 按照 static 初始化方式。
- #include <iostream>
- #include <stdio.h>
- using namespace std;
- class MyTest
- {
- public:
- MyTest():
- m_ConstString("My Test !!!")
- {
- }
- void printMyTest()
- {
- std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
- std::cout << "m_ConstString=" << m_ConstString << endl;
- std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
- }
- private:
- const int m_ConstVarInt = 100; // 成員只有 const, 特殊情況C+11特性, non-static data member initializers only available with -std=c++11 or -std=gnu++11
- const std::string m_ConstString; // 成員只有 const
- static const int mStaticConstVarInt; //成員既有 const 又有 static
- };
- const int MyTest::mStaticConstVarInt = 1000;
- int main()
- {
- MyTest test;
- test.printMyTest();
- return 0;
- }
程序運行結果:
- m_ConstVarInt=100
- m_ConstString=My Test !!!
- mStaticConstVarInt=1000
2. const 重載
類中函數只有 const 屬性不同, 可以進行函數重載(注意, 普通函數不可以)
- #include <iostream>
- #include <stdio.h>
- using namespace std;
- class MyTest
- {
- public:
- MyTest():
- m_ConstString("My Test !!!")
- {
- }
- void printMyTest()
- {
- std::cout << "printMyTest !!!!!" << endl;
- std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
- std::cout << "m_ConstString=" << m_ConstString << endl;
- std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
- }
- void printMyTest() const
- {
- std::cout << "printMyTest const !!!!!" << endl;
- std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
- std::cout << "m_ConstString=" << m_ConstString << endl;
- std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
- }
- private:
- const int m_ConstVarInt = 100; // 成員只有 const, 特殊情況C+11特性, non-static data member initializers only available with -std=c++11 or -std=gnu++11
- const std::string m_ConstString; // 成員只有 const
- static const int mStaticConstVarInt; // 成員既有 const 又有 static
- };
- const int MyTest::mStaticConstVarInt = 1000;
- int main()
- {
- const MyTest testConst;
- //訪問重載的const成員
- testConst.printMyTest();
- MyTest test;
- //訪問重載的非const成員
- test.printMyTest();
- return 0;
- }
程序運行結果:
- printMyTest const !!!!!
- m_ConstVarInt=100
- m_ConstString=My Test !!!
- mStaticConstVarInt=1000
- printMyTest !!!!!
- m_ConstVarInt=100
- m_ConstString=My Test !!!
- mStaticConstVarInt=1000
3 const 類對象
const 類對像只能訪問 const 成員
- #include <iostream>
- #include <stdio.h>
- using namespace std;
- class MyTest
- {
- public:
- MyTest():
- m_ConstString("My Test !!!")
- {
- }
- void printMyTest()
- {
- std::cout << "printMyTest !!!!!" << endl;
- std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
- std::cout << "m_ConstString=" << m_ConstString << endl;
- std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
- }
- void printMyTest() const
- {
- std::cout << "printMyTest const !!!!!" << endl;
- std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
- std::cout << "m_ConstString=" << m_ConstString << endl;
- std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
- }
- void printConstVarInt()
- {
- std::cout << "printConstVarInt !!!!!" << endl;
- std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
- }
- private:
- const int m_ConstVarInt = 100; // 成員只有 const, 特殊情況C+11特性, non-static data member initializers only available with -std=c++11 or -std=gnu++11
- const std::string m_ConstString; // 成員只有 const
- static const int mStaticConstVarInt; // 成員既有 const 又有 static
- };
- const int MyTest::mStaticConstVarInt = 1000;
- int main()
- {
- const MyTest testConst;
- // 可以訪問
- testConst.printMyTest();
- // 不可以訪問, 會報錯
- // testConst.printConstVarInt();
- return 0;
- }
程序運行結果:
- printMyTest const !!!!!
- m_ConstVarInt=100
- m_ConstString=My Test !!!
- mStaticConstVarInt=1000
4 const 函數改變成員變數
可以使用 mutable 在const 函數的內部改變成員變數
- #include <iostream>
- #include <stdio.h>
- using namespace std;
- class MyTest
- {
- public:
- MyTest():
- m_ConstString("My Test !!!")
- {
- }
- void printMyTest()
- {
- std::cout << "printMyTest !!!!!" << endl;
- std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
- std::cout << "m_ConstString=" << m_ConstString << endl;
- std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
- }
- void printMyTest() const
- {
- std::cout << "printMyTest const !!!!!" << endl;
- // 成員變數遞增
- m_VarInt++;
- std::cout << "m_VarInt=" << m_VarInt << endl;
- std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
- std::cout << "m_ConstString=" << m_ConstString << endl;
- std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
- }
- private:
- const int m_ConstVarInt = 100; // 成員只有 const, 特殊情況C+11特性, non-static data member initializers only available with -std=c++11 or -std=gnu++11
- const std::string m_ConstString; // 成員只有 const
- static const int mStaticConstVarInt; // 成員既有 const 又有 static
- mutable int m_VarInt; // 普通成員, mutable 可以在const成員函數裡面改變值
- };
- const int MyTest::mStaticConstVarInt = 1000;
- int main()
- {
- const MyTest testConst;
- // 第一次調用
- testConst.printMyTest();
- // 第二次調用
- testConst.printMyTest();
- return 0;
- }
程序運行結果:
- printMyTest const !!!!!
- m_varInt=1
- m_ConstVarInt=100
- m_ConstString=My Test !!!
- mStaticConstVarInt=1000
- printMyTest const !!!!!
- m_varInt=2
- m_ConstVarInt=100
- m_ConstString=My Test !!!
- 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
- #include <iostream>
- #include <stdio.h>
- using namespace std;
- class Test
- {
- public:
- Test(const int varInt = 100):
- m_VarInt(varInt)
- {
- }
- // 返回值沒有 const
- Test operator+(const Test& test)
- {
- Test tmpTest;
- tmpTest.m_VarInt = this->m_VarInt + test.getVarInt();
- return tmpTest;
- }
- int getVarInt()const
- {
- return m_VarInt;
- }
- private:
- int m_VarInt;
- };
- int main()
- {
- Test testOne(100);
- Test testTwo(200);
- Test testThree(0);
- //這種異常情況, 竟然可以賦值沒有編譯和運行報錯提示
- (testOne + testTwo) = testThree;
- return 0;
- }
(a) 案例2:const 返回值, 編譯報錯處理, 可以保證下述異常不會發生
(testOne + testTwo) = testThree
- #include <iostream>
- #include <stdio.h>
- using namespace std;
- class Test
- {
- public:
- Test(const int varInt = 100):
- m_VarInt(varInt)
- {
- }
- // 返回值加上 const
- const Test operator+(const Test& test)
- {
- Test tmpTest;
- tmpTest.m_VarInt = this->m_VarInt + test.getVarInt();
- return tmpTest;
- }
- int getVarInt()const
- {
- return m_VarInt;
- }
- private:
- int m_VarInt;
- };
- int main()
- {
- Test testOne(100);
- Test testTwo(200);
- Test testThree(0);
- //這種異常情況, 編譯編譯不能通過, 會報錯處理
- (testOne + testTwo) = testThree;
- return 0;
- }
6 const 參數
C++引用------( 臨時變數、引用參數和const引用 )
如果實參與引用參數不匹配,C++將生成臨時變數。如果引用參數是const,則編譯器在下面兩種情況下生成臨時變數:
實參類型是正確的,但不是左值
實參類型不正確,但可以轉換為正確的類型
左值參數是可被引用的數據對象,例如,變數、數組元素、結構成員、引用和被解除引用的指針都是左值,非左值包括字面常量和包含多項式的表達式。定義一個函數
- double refcube(const double& ra)
- {
- return ra*ra*ra;
- }
- double side = 3.0;
- double* pd = &side;
- double& rd = side;
- long edge = 5L;
- double lens[4]={2.3,3.4,4.5,6.7};
- double c1 = refcube(side); // ra 是side
- double c2 = refcube(lens[2]); // ra是lens[2]
- double c3 = refcube(rd); // ra 是 rd
- double c4 = refcube(*pd); // ra 是*pd
- double c5 = refcube(edge); // ra 是臨時變數
- double c6 = refcube(7.0); // ra 是臨時變數
- double c7 = refcube(side+10.0); // ra 是臨時變數
參數side lens[2] rd 和*pd都是有名稱的、double類型的數據對象,因此可以為其創建引用,而不需要臨時變數。但是edge雖然是變數,類型卻不正確,double引用不能指向long。另一方面,參數7.0和side+10.0的類型都正確,但沒有名稱,在這些情況下,編譯器都將生成一個臨時匿名變數,並讓ra指向它。這些臨時變數只在函數調用期間存在,伺候編譯器便可以任意將其刪除
那麼為什麼對於常量引用,這種行為是可行的,其他情況下卻不行呢?
- void swapr(int& a,int& b)
- {
- int temp;
- temp=a;
- a = b;
- b = temp;
- }
在早期的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引用使函數能夠正確生成並使用臨時變數
※mysql定時任務和存儲過程的小例子
※程序員如何快速搭建個性化主頁
TAG:程序員小新人學習 |