C++中有關 const & 內斂 & 友元&靜態成員 的用法比較雜亂,算是C++中一個麻煩的部分。現速速的對它們作大體的總結,瞭解它們當中常見的用法和陷阱。ios
在成員函數後面加const,const修飾this指針所指向的對象,也就是保證調用這個const成員函數的對象在函數內不會改變安全
/************************************************************************* > File Name: 2.cc > Author: tp > Mail: > Created Time: Tue 19 Jun 2018 05:48:12 PM CST ************************************************************************/ #include <iostream> #include <cstdio> #include <vector>
using namespace std; class Date { public : Date(int y=0, int m =0, int d=0) :_year(y),_month( m),_day( d){ } void Display ( ) { cout<<" Display ( ) " <<endl; cout<<" year:" <<_year<< endl; cout<<" month:" <<_month<< endl; cout<<" day:" <<_day<< endl<<endl ; } void Display ( ) const { cout<<" Display ( ) const" <<endl; cout<<" year:" <<_year<< endl; cout<<" month:" <<_month<< endl; cout<<" day:" <<_day<< endl<<endl; } private : int _year ; // 年
int _month ; // 月
int _day ; // 日
}; int main( ) { Date d1; d1.Display ( ) ; const Date d2; d2.Display(); return 0; }
常見情景:函數
1. const對象能夠調用非const成員函數和const成員函數嗎?優化
只能調用const成員函數。由於是const對象,它就要求對象內部數據初始化好不會改變,因此其相應成員函數也應由const修飾。this
#include <iostream> #include <cstdio> #include <vector> using namespace std; class Date { public : Date(int y=0, int m =0, int d=0) :_year(y),_month( m),_day( d){ } void Display ( ) { cout<<" Display ( ) " <<endl; cout<<" year:" <<_year<< endl; cout<<" month:" <<_month<< endl; cout<<" day:" <<_day<< endl<<endl; } private : int _year ; // 年 int _month ; // 月 int _day ; // 日 }; int main( ) { // Date d1; // d1.Display ( ) ; const Date d2; d2.Display(); return 0; } //結果:報錯!
2. 非const對象能夠調用非const成員函數和const成員函數嗎?spa
均可以調用。調用非const成員函數沒有爭議,當非const對象調用const成員函數時,對非const對象來講,這實際上是一個權限的縮小,是能夠完成的。debug
#include <iostream> #include <cstdio> #include <vector> using namespace std; class Date { public : Date(int y=0, int m =0, int d=0) :_year(y),_month( m),_day( d){ } void Display ( ) const { cout<<" Display ( ) const" <<endl; cout<<" year:" <<_year<< endl; cout<<" month:" <<_month<< endl; cout<<" day:" <<_day<< endl<<endl; } private : int _year ; // 年 int _month ; // 月 int _day ; // 日 }; int main( ) { Date d1; d1.Display ( ) ; // const Date d2; // d2.Display(); return 0; } //結果:成功調用
3. const成員函數內能夠調用其它的const成員函數非const成員函數嗎?指針
在const成員函數中是不能調用非const成員函數。道理同上
4. 非const成員函數內能夠調用其它的const成員函數非const成員函數嗎?調試
非const成員函數既能夠掉非const成員函數 也能夠調用const成員函數(道理類似,非const成員函數至關於一次權限縮小)code
關於內斂,內斂就是以inline修飾的函數叫作內聯函數,編譯時C++編譯器會在調用內聯函數的地方插入代碼進行展開,沒有
函數壓棧的開銷,內聯函數提高程序運行的效率。
關於內斂的幾點注意:
·inline是一種以空間換時間的作法,省去調用函數額開銷。因此代碼很長或者有循環/遞歸的的函數不適宜使用內聯。
·inline對於編譯器而言只是一個建議,編譯器會自動優化,若是定義爲inline的函數體內有循環/遞歸等等,編譯器優化時會忽略掉內聯。
·inline必須和函數定義放在一塊兒,才能成爲內聯函數,僅僅將inline關鍵字放到聲明前是不起做用的。
·定義在類內的成員函數默認爲內聯函數。
·debug版本下的內斂函數不展開,因此它能夠像普通函數那樣進行調試。
class Date { public : void Func () // 定義在類內部默認爲內聯函數
{} void Display (); private : int _year ; // 年
int _month ; // 月
int _day ; // 日
}; inline void Date::Display () // 成員函數定義爲內聯
{ cout<<"year:" <<_year<< endl; cout<<"month:" <<_month<< endl; cout<<"day:" <<_day<< endl; } inline void Test() // 全局函數定義爲內聯
{}
內斂和宏區別:
·最大的區別在於宏是在預處理階段處理,而內斂是在編譯階段來進行處理。
·預處理階段發生宏替換,但替換僅僅是單純的文本替換,不做類型安全的檢查,同時它也不能去訪存私有的數據成員;
·而內斂在編譯階段進行的處理,它有類型安全的檢查(即調用一個內聯函數時,編譯器首先確保正確,即全部的參數類型必須是正確的或者編譯器必須可以將類型轉換爲正確類型,而且返回值在目標表達式裏應該是正確的類型或者能夠改變爲正確的類型),同時也能夠訪存私有的數據成員。
總結來講就是內斂能夠像宏同樣能夠提升代碼執行效率,但內斂還能夠進行類型安全檢查,訪問私有數據成員,因此可儘可能用內斂去替代宏。
在C++中友元函數容許在類外訪問該類中的任何成員,就象成員函數同樣,友元函數用關鍵字friend說明。
關於友元:
1. 友元函數不是類的成員函數。
2. 友元函數能夠經過對象訪問全部成員,私有和保護成員也同樣。
一個典型的例子:
重載自定義類型的輸入(>>) 輸出(<<)
class Date { public : // operator<<不能爲成員函數 // 返回值定義爲輸入輸出流的引用。
friend ostream& operator<< ( ostream& os , const Date& d ); friend istream& operator>> ( istream& is , Date& d); private : int _year ; // 年
int _month ; // 月
int _day ; // 日
}; ostream& operator<<( ostream& os , const Date& d) { os<<"year:" <<d. _year<<endl ; os<<"month:" <<d. _month<<endl ; os<<"day:" <<d. _day<<endl <<endl; return os ; } // cin.operator<<(cin, d1) istream& operator>> ( istream& is , Date& d) { cout<<" 請分別輸入年月日: "<<endl ; is>>d ._year; is>>d ._month; is>>d ._day; return is ; } void Test () { Date d1 ; cin>>d1 ; cout<<d1 ; }
爲何說<<, >>操做符重載函數 不能是成員函數?
class Date { public : ostream& operator<< (ostream& os) ; istream& operator>> (istream& is) ; private : int _year ; // 年
int _month ; // 月
int _day ; // 日
} ; ostream& Date::operator<<(ostream& os) { os<<" year:" << _year<<endl ; os<<" month:" << _month<<endl ; os<<" day:" << _day<<endl <<endl; return os ; } // cin.operator<<( cin, d1)
istream& Date::operator>> (istream& is) { cout<<" 請分別輸入年月日: " <<endl ; is>>_year; is>>_month; is>>_day; return is ; } void Test ( ) { Date d1 ; d1>>cin; d1<<cout; }
不難注意到最後咱們調用>> <<操做符時,將成爲一種怪異的操做!估計是難以讓人接受的。
究其緣由,不難發現實際上是由this指針致使的。由於this指針會默認會用成員函數的第一個位置,其它傳進來的參數(這裏的ostream 、istream)都只能溜到它後面去玩,因此纔會導致cin、cout跑到「>>」,"<<"的右邊去。想要像正常狀況那樣使用cin cout,咱們就只有不把它們寫成成員函數了,這樣就沒有this指針來搶位子了。可是,這無疑又將引來一個問題:因爲函數須要訪問傳入進來的輸入、輸出對象,但此時對象的成員是被封裝的,函數訪問必然就會失敗。
因此最後要解決這個問題,咱們就只有將「opetator >>」,"operator<<"函數定義爲Date類的友元函數了,這樣即可經過對象來訪問其中的數據成員了,最後完成目的。
從這裏也容易看出用友元,實際上是一種破壞封裝的行爲。
除此友元函數以外還有友元類
友元類:整個類能夠是另外一個類的友元。友元類的每一個成員函數都是另外一個類的友元函數,均可訪問另外一個類中的保護或私有數據成員。
類裏面static修飾的成員,成爲靜態類成員。它最大的特色就是:類的靜態成員是該類型的全部對象對象所共享。
注意:靜態成員函數沒有隱含的this指針參數,因此可使用類型::做用域訪問符直接調用靜態成員函數。
#include <iostream> #include <cstdio> #include <vector>
using namespace std; class Date { public : Date() { cout<<"Date( )"<<endl; ++dCount; } static void printCount( ) { cout<<"Date::dCount:"<<dCount<<endl;; } private : static int dCount; } ; //定義並初始化靜態成員
int Date::dCount = 0; void Test( ) { Date d1 ; d1.printCount( ); //1
Date d2 ; Date d3 ; //能夠直接用類名加類域限定符調用
Date::printCount( ); //3
}
關於靜態成員一點思考:
1. 靜態成員函數能夠訪問非靜態的成員嗎?
不能夠,由於靜態成員函數沒有this指針。因爲非靜態數據成員是存儲在對象中,成員函數訪問數據成員要藉助this指針,因此沒有this指針的靜態成員函數不能訪問非靜態數據成員。
2. 非靜態的成員函數能夠訪問靜態成員嗎?
能夠的,靜態數據成員存儲在地址空間的數據段,它爲該類的全部對象共享,這些對象的成員函數天然也能夠訪問。