C++中const——由一个例子想到的
前天同學實現(xiàn)了《C++ Primer》中關(guān)于虛函數(shù)的一個例子,拿過來問我,代碼如下:
#include<iostream> #include<string> using namespace std;class Item{ public:Item(const string x,const double y){isbn=x;price=y;};virtual double net_price(size_t n) const{return n*price;};//可以去掉virtual體驗到第3、4行打印出來的區(qū)別virtual ~Item(){};string isbn; protected:double price; };class Bulk_Item:public Item{ public:Bulk_Item(const string x,const double y,const size_t z,const double w):Item(x,y),min_qty(z),discount(w){};double net_price(size_t n) const;//double get() const;//double get(); private:size_t min_qty;double discount; };double Bulk_Item::net_price(size_t n) const{if(n>=min_qty) return n*(1-discount)*price;else return n*price; }void print_total(const Item &it,size_t n){cout<<it.isbn<<"\tnumber sold: "<<n<<"\ttotal price: "<<it.net_price(n)<<endl; }int main(){Item it1("201307291540",16.5);cout<<it1.net_price(2)<<endl;Bulk_Item it2("201307291545",22.5,10,0.2);cout<<it2.net_price(20)<<endl;print_total(it1,4);print_total(it2,20);return 0; }?
?同學的疑問是,如果去掉 Item 類定義中
virtual double net_price(size_t n) const{return n*price;};?
一句中的 const 限定,則會在print_total 的定義行出現(xiàn)編譯錯誤
“Item::net_price”: 不能將“this”指針從“const Item”轉(zhuǎn)換為“Item &”他覺得定義的 net_price 方法并沒有修改 Item 內(nèi)的屬性,有沒有const限定詞應該是一樣的。
但實際上,在print_total 的定義中,限定了引用 it 為 const, 這意味著該引用只能調(diào)用 Item 類內(nèi)的 const方法,即:const限定的對象引用不能調(diào)用此對象中的非const方法。
進而,可以知道,C++中判斷一個方法是不是const,并不是檢測你在該方法中有沒有改變類的屬性,而只是簡單的看你有沒有const限定詞,有就是const方法,沒有就不是const方法。若有const限定詞,而在方法內(nèi)你又試圖改變類的屬性,則編譯器會報錯。
?
那么,同名函數(shù)(包括參數(shù)相同),一個有const限定,一個沒有,是兩個函數(shù)還是一個函數(shù)?為了探究,在?Bulk_Item 的定義中增加兩個 get_price 函數(shù),一個為const,一個為普通函數(shù),然后在主函數(shù)里調(diào)用:
#include<iostream> #include<string> using namespace std;class Item{ public:Item(const string x,const double y){isbn=x;price=y;};virtual double net_price(size_t n) const{return n*price;};//可以去掉virtual體驗到第3、4行打印出來的區(qū)別virtual ~Item(){};string isbn; protected:double price; };class Bulk_Item:public Item{ public:Bulk_Item(const string x,const double y,const size_t z,const double w):Item(x,y),min_qty(z),discount(w){};double net_price(size_t n) const;double get_price() const{cout<<"get const"<<endl;return price;};double get_price(){cout<<"get Non const"<<endl;return price; };private:size_t min_qty;double discount; };double Bulk_Item::net_price(size_t n) const{if(n>=min_qty) return n*(1-discount)*price;else return n*price; }void print_total(const Item &it,size_t n){cout<<it.isbn<<"\tnumber sold: "<<n<<"\ttotal price: "<<it.net_price(n)<<endl; }int main(){Item it1("201307291540",16.5);cout<<it1.net_price(2)<<endl;Bulk_Item it2("201307291545",22.5,10,0.2);cout<<it2.net_price(20)<<endl;print_total(it1,4);print_total(it2,20); cout<<it2.get_price()<<endl;return 0; }?
輸出結(jié)果為:
get Non const 22.5可見,并沒有產(chǎn)生編譯錯誤,自動調(diào)用的是非const方法。故有無const會造成有兩個重載的函數(shù),編譯后的函數(shù)名,除了函數(shù)名和參數(shù),還加入了const限定詞。但調(diào)用時會優(yōu)先選非const的函數(shù)(這是因為我們傳入的是非const對象it2,下面會看到,若傳入const對象,則自動調(diào)用const版本)。
接著,我們構(gòu)造打印函數(shù),如下:
#include<iostream> #include<string> using namespace std;class Item{ public:Item(const string x,const double y){isbn=x;price=y;};virtual double net_price(size_t n) const{return n*price;};//可以去掉virtual體驗到第3、4行打印出來的區(qū)別virtual ~Item(){};string isbn; protected:double price; };class Bulk_Item:public Item{ public:Bulk_Item(const string x,const double y,const size_t z,const double w):Item(x,y),min_qty(z),discount(w){};double net_price(size_t n) const;double get_price() const{cout<<"get const"<<endl;return price;};double get_price(){cout<<"get Non const"<<endl;return price; };private:size_t min_qty;double discount; };double Bulk_Item::net_price(size_t n) const{if(n>=min_qty) return n*(1-discount)*price;else return n*price; }void print_total(const Item &it,size_t n){cout<<it.isbn<<"\tnumber sold: "<<n<<"\ttotal price: "<<it.net_price(n)<<endl; }void print_price(const Bulk_Item &it){cout<<"print_price const"<<endl;cout<<it.get_price()<<endl; }void print_price(Bulk_Item &it){cout<<"print_price Non const"<<endl;cout<<it.get_price()<<endl; }int main(){Item it1("201307291540",16.5);cout<<it1.net_price(2)<<endl;Bulk_Item it2("201307291545",22.5,10,0.2);cout<<it2.net_price(20)<<endl;print_total(it1,4);print_total(it2,20);cout<<it2.get_price()<<endl; print_price(it2);return 0; }?
輸出結(jié)果為:
print_price Non const get Non const 22.5?
可見,(1)調(diào)用時,優(yōu)先調(diào)用參數(shù)為非const的函數(shù)(因為傳入的it2是非const參數(shù)),編譯器不會在你傳入非const參數(shù)時調(diào)用const參數(shù)的函數(shù)(除非沒有非const版本),這是合理的,否則你不能改變你想改變的;(2)函數(shù)內(nèi),自動調(diào)用非const版本get_price(因為傳入的是非const引用,故優(yōu)先調(diào)用get_price方法的非const版本)。
同理,如果傳入const 參數(shù),如下:
#include<iostream> #include<string> using namespace std;class Item{ public:Item(const string x,const double y){isbn=x;price=y;};virtual double net_price(size_t n) const{return n*price;};//可以去掉virtual體驗到第3、4行打印出來的區(qū)別virtual ~Item(){};string isbn; protected:double price; };class Bulk_Item:public Item{ public:Bulk_Item(const string x,const double y,const size_t z,const double w):Item(x,y),min_qty(z),discount(w){};double net_price(size_t n) const;double get_price() const{cout<<"get const"<<endl;return price;};double get_price(){cout<<"get Non const"<<endl;return price; };private:size_t min_qty;double discount; };double Bulk_Item::net_price(size_t n) const{if(n>=min_qty) return n*(1-discount)*price;else return n*price; }void print_total(const Item &it,size_t n){cout<<it.isbn<<"\tnumber sold: "<<n<<"\ttotal price: "<<it.net_price(n)<<endl; }void print_price(const Bulk_Item &it){cout<<"print_price const"<<endl;cout<<it.get_price()<<endl; }void print_price(Bulk_Item &it){cout<<"print_price Non const"<<endl;cout<<it.get_price()<<endl; }int main(){Item it1("201307291540",16.5);cout<<it1.net_price(2)<<endl;Bulk_Item it2("201307291545",22.5,10,0.2);cout<<it2.net_price(20)<<endl;print_total(it1,4);print_total(it2,20);cout<<it2.get_price()<<endl;print_price(it2);const Bulk_Item it3("201307291546",44,10,0.2);print_price(it3);return 0; }?
則會打印:
print_price const get const 44?
說明,(1)傳入const參數(shù)會調(diào)用參數(shù)為const的函數(shù),這是理所應當?shù)?#xff1b;(2)在print_price里會調(diào)用const版本的get_price,這說明,如果我們對一個類,有同名的兩個函數(shù),一個為const,一個非const,若用一個const對象引用來調(diào)用這個同名函數(shù),則自動調(diào)用那個const函數(shù)。如下所示:
#include<iostream> #include<string> using namespace std;class Item{ public:Item(const string x,const double y){isbn=x;price=y;};virtual double net_price(size_t n) const{return n*price;};//可以去掉virtual體驗到第3、4行打印出來的區(qū)別virtual ~Item(){};string isbn; protected:double price; };class Bulk_Item:public Item{ public:Bulk_Item(const string x,const double y,const size_t z,const double w):Item(x,y),min_qty(z),discount(w){};double net_price(size_t n) const;double get_price() const{cout<<"get const"<<endl;return price;};double get_price(){cout<<"get Non const"<<endl;return price; };private:size_t min_qty;double discount; };double Bulk_Item::net_price(size_t n) const{if(n>=min_qty) return n*(1-discount)*price;else return n*price; }void print_total(const Item &it,size_t n){cout<<it.isbn<<"\tnumber sold: "<<n<<"\ttotal price: "<<it.net_price(n)<<endl; }void print_price(const Bulk_Item &it){cout<<"print_price const"<<endl;cout<<it.get_price()<<endl; }void print_price(Bulk_Item &it){cout<<"print_price Non const"<<endl;cout<<it.get_price()<<endl; }int main(){Item it1("201307291540",16.5);cout<<it1.net_price(2)<<endl;Bulk_Item it2("201307291545",22.5,10,0.2);cout<<it2.net_price(20)<<endl;print_total(it1,4);print_total(it2,20);cout<<it2.get_price()<<endl;print_price(it2);const Bulk_Item it3("201307291546",44,10,0.2);cout<<it3.get_price()<<endl;print_price(it3);return 0; }?則會打印:
get const 44?故而,鑒于有無const限定詞會造就兩個不同的函數(shù),所以如果基類中有const,而繼承類中同名方法沒有const,則其實繼承類實現(xiàn)的是一個完全新的函數(shù),而不是在覆蓋基類的方法。向上類型轉(zhuǎn)換時,會調(diào)用基類的方法,而不是繼承類中同名的非const方法,如下:
#include<iostream> #include<string> using namespace std;class Item{ public:Item(const string x,const double y){isbn=x;price=y;};virtual double net_price(size_t n) const{return n*price;};//可以去掉virtual體驗到第3、4行打印出來的區(qū)別virtual ~Item(){};string isbn; protected:double price; };class Bulk_Item:public Item{ public:Bulk_Item(const string x,const double y,const size_t z,const double w):Item(x,y),min_qty(z),discount(w){};double net_price(size_t n) ;private:size_t min_qty;double discount; };double Bulk_Item::net_price(size_t n) {if(n>=min_qty) return n*(1-discount)*price;else return n*price; }void print_total(const Item &it,size_t n){cout<<it.isbn<<"\tnumber sold: "<<n<<"\ttotal price: "<<it.net_price(n)<<endl; }int main(){Item it1("201307291540",16.5);cout<<it1.net_price(2)<<endl;Bulk_Item it2("201307291545",22.5,10,0.2);cout<<it2.net_price(20)<<endl;print_total(it1,4);print_total(it2,20);return 0; }最后一行輸出為450而不是360。
同理,若基類方法無const,而繼承類中有,則向上類型轉(zhuǎn)換還是會調(diào)用基類的方法。
總結(jié)一下,主要有這么幾點:
1、const限定的對象引用不能調(diào)用此對象中的非const方法。
2、const關(guān)鍵詞限定的方法,則編譯器就認為它是const型的,即使它并沒有改變對象的任何屬性。若限定了const,又在方法內(nèi)改變了屬性,則編譯器會報錯。
3、同名函數(shù)(參數(shù)也相同),一個有const限定,一個沒有,編譯器認為是兩個重載函數(shù),不會報錯。這就意味著C++中編譯器生成函數(shù)名時,除了函數(shù)名、參數(shù)外還有const,由三者共同組成編譯后的函數(shù)名。
4、如上,兩個方法的方法名和參數(shù)完全相同,一個有const限定,一個沒有,則若你用const對象引用調(diào)用,會自動調(diào)用const版本的方法;若用非const對象引用調(diào)用,則會自動調(diào)用非const的版本。
5、同樣的函數(shù),只是參數(shù)一個是const,一個非const,則你用const參數(shù)調(diào)用,會自動調(diào)用參數(shù)為const的版本;你用普通參數(shù)調(diào)用,會自動調(diào)用參數(shù)為普通參數(shù)的版本,若此時沒有非const的版本,它才會轉(zhuǎn)而調(diào)用const版本的。
6、如果基類中有const,而繼承類中同名方法沒有const,則其實繼承類實現(xiàn)的是一個完全新的函數(shù),而不是在覆蓋基類的方法,向上類型轉(zhuǎn)換時,會調(diào)用基類的方法,而不是繼承類中同名的非const方法。
突然想到,學習一門語言的最好方式也就就是:寫一個這個語言的編譯器。這樣你就能對它的限制,它能做什么和不能做什么,你能用它做什么和不能做什么,有比較深刻的理解和記憶。推而廣之,人類語言有很多冗余性,語法限制也相對比較寬松,故人類語言的編譯器應該很難寫。若能寫一個人類語言的編譯器,那就是真正的自然語言理解。
轉(zhuǎn)載于:https://www.cnblogs.com/rolling-stone/p/3223454.html
總結(jié)
以上是生活随笔為你收集整理的C++中const——由一个例子想到的的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Event Aggregator
- 下一篇: 将动态库添加到VC程序中