精品文章 論C++構(gòu)造函數(shù)中的不合理設(shè)計
在C++中,構(gòu)造函數(shù)是一個在構(gòu)件對象的時候調(diào)用的特殊的函數(shù),其目的是對對象進(jìn)行初始化的工作,從而使對象被使用之前可以處于一種合理的狀態(tài)。但是,構(gòu)造函數(shù)的設(shè)計并不完美,甚至有些不合理的特性。比如說,限定構(gòu)造函數(shù)名稱與類的名稱相同的條件。這些特性在構(gòu)造C++編譯器的時候是值得引起注意的。還有,在今后C++的標(biāo)準(zhǔn)修訂或者制定其他面向?qū)ο蟮脑O(shè)計語言時候應(yīng)當(dāng)避免這些特性。這里也提出了一些解決的方案。
C++中,任何類都有一個(至少有一個)構(gòu)造函數(shù),甚至在沒有構(gòu)造函數(shù)被聲明的時候亦是如此。在對象被聲明的時候,或者被動態(tài)生成的時候,這些構(gòu)造函數(shù)就會被調(diào)用。構(gòu)造函數(shù)做了許多不可見的工作,即使構(gòu)造函數(shù)中沒有任何代碼,這些工作包括對對象的內(nèi)存分配和通過賦值的方式對成員進(jìn)行初始化。構(gòu)造函數(shù)的名稱必須與類的名稱相同,但是可以有許多不同的重載版本來提供,通過參數(shù)類型來區(qū)分構(gòu)造函數(shù)的版本。構(gòu)造函數(shù)可以顯式的通過用戶代碼來調(diào)用,或者當(dāng)代碼不存在是通過編譯程序來隱式插入。當(dāng)然,顯式地通過代碼調(diào)用是推薦的方法,因為隱式調(diào)用的效果可能不是我們所預(yù)料的,特別是在處理動態(tài)內(nèi)存分配方面。代碼通過參數(shù)來調(diào)用唯一的構(gòu)造函數(shù)。構(gòu)造函數(shù)沒有返回值,盡管在函數(shù)體中可以又返回語句。每個構(gòu)造函數(shù)可以以不同的方式來實例化一個對象,因為每個類都有構(gòu)造函數(shù),至少也是缺省構(gòu)造函數(shù),所以每個對象在使用之前都相應(yīng)的使用構(gòu)造函數(shù)。
因為構(gòu)造函數(shù)是一種函數(shù),所以他的可見性無非是三種public、private、protected。通常,構(gòu)造函數(shù)都被聲明為public型。如果構(gòu)造函數(shù)被聲明為private或protected,就限制了對象的實例化。這在阻止類被其他人實例化的方面很有效。構(gòu)造函數(shù)中可以有任何C++的語句,比如,一條打印語句,可以被加入到構(gòu)造函數(shù)中來表明調(diào)用的位置。
#p#
構(gòu)造函數(shù)的類型
C++中構(gòu)造函數(shù)有許多種類型,最常用的式缺省構(gòu)造函數(shù)和拷貝構(gòu)造函數(shù),也存在一些不常用的構(gòu)造函數(shù)。下面介紹了四種不同的構(gòu)造函數(shù)。
1、缺省構(gòu)造函數(shù)
缺省構(gòu)造函數(shù)是沒有參數(shù)的函數(shù)。另外,缺省構(gòu)造函數(shù)也可以在參數(shù)列表中以參數(shù)缺省值的方式聲明。缺省構(gòu)造函數(shù)的作用是把對象初始化為缺省的狀態(tài)。如果在類中沒有顯式定義構(gòu)造函數(shù),那么編譯器會自動的隱式創(chuàng)建一個,這個隱式創(chuàng)建的構(gòu)造函數(shù)和一個空的構(gòu)造函數(shù)很相像。他除了產(chǎn)生對象的實例以外什么工作都不做。在許多情況下,缺省構(gòu)造函數(shù)都會被自動的調(diào)用,例如在一個對象被聲明的時候,就會引起缺省構(gòu)造函數(shù)的調(diào)用。
2、拷貝構(gòu)造函數(shù)
拷貝構(gòu)造函數(shù),經(jīng)常被稱作X(X&),是一種特殊的構(gòu)造函數(shù),他由編譯器調(diào)用來完成一些基于同一類的其他對象的構(gòu)件及初始化。它的唯一的一個參數(shù)(對象的引用)是不可變的(因為是const型的)。這個函數(shù)經(jīng)常用在函數(shù)調(diào)用期間于用戶定義類型的值傳遞及返回??截悩?gòu)造函數(shù)要調(diào)用基類的拷貝構(gòu)造函數(shù)和成員函數(shù)。如果可以的話,它將用常量方式調(diào)用,另外,也可以用非常量方式調(diào)用。
在C++中,下面三種對象需要拷貝的情況。因此,拷貝構(gòu)造函數(shù)將會被調(diào)用。
1). 一個對象以值傳遞的方式傳入函數(shù)體
2). 一個對象以值傳遞的方式從函數(shù)返回
3). 一個對象需要通過另外一個對象進(jìn)行初始化
以上的情況需要拷貝構(gòu)造函數(shù)的調(diào)用。如果在前兩種情況不使用拷貝構(gòu)造函數(shù)的時候,就會導(dǎo)致一個指針指向已經(jīng)被刪除的內(nèi)存空間。對于第三種情況來說,初始化和賦值的不同含義是構(gòu)造函數(shù)調(diào)用的原因。事實上,拷貝構(gòu)造函數(shù)是由普通構(gòu)造函數(shù)和賦值操作賦共同實現(xiàn)的。描述拷貝構(gòu)造函數(shù)和賦值運算符的異同的參考資料有很多。
拷貝構(gòu)造函數(shù)不可以改變它所引用的對象,其原因如下:當(dāng)一個對象以傳遞值的方式傳一個函數(shù)的時候,拷貝構(gòu)造函數(shù)自動的被調(diào)用來生成函數(shù)中的對象。如果一個對象是被傳入自己的拷貝構(gòu)造函數(shù),它的拷貝構(gòu)造函數(shù)將會被調(diào)用來拷貝這個對象這樣復(fù)制才可以傳入它自己的拷貝構(gòu)造函數(shù),這會導(dǎo)致無限循環(huán)。
除了當(dāng)對象傳入函數(shù)的時候被隱式調(diào)用以外,拷貝構(gòu)造函數(shù)在對象被函數(shù)返回的時候也同樣的被調(diào)用。換句話說,你從函數(shù)返回得到的只是對象的一份拷貝。但是同樣的,拷貝構(gòu)造函數(shù)被正確的調(diào)用了,你不必?fù)?dān)心。
如果在類中沒有顯式的聲明一個拷貝構(gòu)造函數(shù),那么,編譯器會私下里為你制定一個函數(shù)來進(jìn)行對象之間的位拷貝(bitwise copy)。這個隱含的拷貝構(gòu)造函數(shù)簡單的關(guān)聯(lián)了所有的類成員。許多作者都會提及這個默認(rèn)的拷貝構(gòu)造函數(shù)。注意到這個隱式的拷貝構(gòu)造函數(shù)和顯式聲明的拷貝構(gòu)造函數(shù)的不同在于對于成員的關(guān)聯(lián)方式。顯式聲明的拷貝構(gòu)造函數(shù)關(guān)聯(lián)的只是被實例化的類成員的缺省構(gòu)造函數(shù)除非另外一個構(gòu)造函數(shù)在類初始化或者在構(gòu)造列表的時候被調(diào)用。
拷貝構(gòu)造函數(shù)是程序更加有效率,因為它不用再構(gòu)造一個對象的時候改變構(gòu)造函數(shù)的參數(shù)列表。設(shè)計拷貝構(gòu)造函數(shù)是一個良好的風(fēng)格,即使是編譯系統(tǒng)提供的幫助你申請內(nèi)存默認(rèn)拷貝構(gòu)造函數(shù)。事實上,默認(rèn)拷貝構(gòu)造函數(shù)可以應(yīng)付許多情況。
3、用戶定義的構(gòu)造函數(shù)
用戶定義的構(gòu)造函數(shù)允許對象在被定義的時候同時被初始化。這種構(gòu)造函數(shù)可以有任何類型的參數(shù)。一個用戶定義的和其它類型的構(gòu)造函數(shù)在類 mystring 中得以體現(xiàn):
- class mystring
- {......
- public: mystring(); // Default constructor
- mystring (mystring &src)
- // Copy constructor
- mystring (char * scr);
- // Coercion constructor
- mystring ( char scr[ ], size_t len);
- // User-Defined constructor
- };
4、強制構(gòu)造函數(shù)
C++中,可以聲明一個只有一個參數(shù)的構(gòu)造函數(shù)來進(jìn)行類型轉(zhuǎn)換。強制構(gòu)造函數(shù)定一個從參數(shù)類型進(jìn)行的一個類型轉(zhuǎn)換(隱式的或顯式的)。換句話說,編譯器可以用任何參數(shù)的實例來調(diào)用構(gòu)造函數(shù)。這樣做的目的是建立一個臨時實例來替換一個參數(shù)類型的實例。注意標(biāo)準(zhǔn)新近加入C++的關(guān)鍵字explicit 是用來禁止隱式的類型轉(zhuǎn)換。然而,這一特性還沒能被所有的編譯器支持。下面是一個強制構(gòu)造函數(shù)的例子:
- class A
- {
- public :
- A(int ){ }
- };
- void f(A) { }
- void g()
- {
- A My_Object= 17;
- A a2 = A(57);
- A a3(64);
- My_Object = 67;
- f(77);
- };
像A My_Object= 17;這種聲明意味著A(int)構(gòu)造函數(shù)被調(diào)用來從整型變量生成一個對象。這樣的構(gòu)造函數(shù)就是強制構(gòu)造函數(shù)。
#p#
不合理普遍特性
下面是一些C++構(gòu)造函數(shù)的不合理設(shè)計,當(dāng)然,可能還有其他一些不合理之處。但是,大多數(shù)情況下,我們還是要和這些特性打交道,我們要逐一說明。
1、構(gòu)造函數(shù)可以為內(nèi)聯(lián),但不要這樣做
一般來講,大多數(shù)成員函數(shù)都可以在前面加入"inline"關(guān)鍵字而成為內(nèi)聯(lián)函數(shù),構(gòu)造函數(shù)也不例外,但是別這么做!一個被定義為內(nèi)聯(lián)的構(gòu)造函數(shù)如下:
- class x
- {..........
- public : x (int );
- :
- :
- };
- inline x::x(int )
- {...}
在上面的代碼中,函數(shù)并不是作為一個單獨的實體而是被插入到程序代碼中。這對于只有一兩條語句的函數(shù)來說會提到效率,因為這里沒有調(diào)用函數(shù)的開銷。
用內(nèi)聯(lián)的構(gòu)造函數(shù)的危險性可以在定義一個靜態(tài)內(nèi)聯(lián)構(gòu)造函數(shù)中體現(xiàn)。在這種情況下,靜態(tài)的構(gòu)造函數(shù)應(yīng)當(dāng)是只被調(diào)用一次。然而,如果頭文件中含有靜態(tài)內(nèi)聯(lián)構(gòu)造函數(shù),并被其他單元包括的話,函數(shù)就會產(chǎn)生多次拷貝。這樣,在程序啟動時就會調(diào)用所有的函數(shù)拷貝,而不是程序應(yīng)當(dāng)調(diào)用的一份拷貝。這其中的根本原因是靜態(tài)函數(shù)是在以函數(shù)偽裝下的真實對象。
應(yīng)該牢記的一件事是內(nèi)聯(lián)是建議而不是強制,編譯器產(chǎn)生內(nèi)聯(lián)代碼。這意味著內(nèi)聯(lián)是與實現(xiàn)有關(guān)的編譯器的不同可能帶來很多差異。另一方面,內(nèi)聯(lián)函數(shù)中可能包括比代碼更多的東西。構(gòu)造函數(shù)被聲明為內(nèi)聯(lián),所有包含對象的構(gòu)造函數(shù)和基類的構(gòu)造函數(shù)都需要被調(diào)用。這些調(diào)用是隱含在構(gòu)造函數(shù)中的。這可能會創(chuàng)建很大的內(nèi)聯(lián)函數(shù)段,所以,不推薦使用內(nèi)聯(lián)的構(gòu)造函數(shù)。
2、構(gòu)造函數(shù)沒有任何返回類型
對一個構(gòu)造函數(shù)指定一個返回類型是一個錯誤,因為這樣會引入構(gòu)造函數(shù)的地址。這意味著將無法處理出錯。這樣,一個構(gòu)造函數(shù)是否成功的創(chuàng)建一個對象將不可以通過返回之來確定。事實上,盡管C++的構(gòu)造函數(shù)不可以返回,也有一個方法來確定是否內(nèi)存分配成功地進(jìn)行。這種方法是內(nèi)建在語言內(nèi)部來處理緊急情況的機制。一個預(yù)定好的函數(shù)指針 new-handler,它可以被設(shè)置為用戶定制的對付new操作符失敗的函數(shù),這個函數(shù)可以進(jìn)行任何的動作,包括設(shè)置錯誤標(biāo)志、重新申請內(nèi)存、退出程序或者拋出異常。你可以安心的使用系統(tǒng)內(nèi)建的new-handler。最好的使構(gòu)造函數(shù)發(fā)出出錯信號的方法,就是拋出異常。在構(gòu)造函數(shù)中拋出異常將清除錯誤之前創(chuàng)建的任何對象及分配的內(nèi)存。
如果構(gòu)造函數(shù)失敗而使用異常處理的話,那么,在另一個函數(shù)中進(jìn)行初始化可能是一個更好的主意。這樣,程序員就可以安全的構(gòu)件對象并得到一個合理的指針。然后,初始化函數(shù)被調(diào)用。如果初始化失敗的話,對象直接被清除。
3、構(gòu)造函數(shù)不可以被聲明為static
C++中,每一個類的對象都擁有類數(shù)據(jù)成員的一份拷貝。但是,靜態(tài)成員則沒有這樣而是所有的對象共享一個靜態(tài)成員。靜態(tài)函數(shù)是作用于類的操作,而不是作用在對象上??梢杂妙惷妥饔每刂撇僮鞣麃碚{(diào)用一個靜態(tài)函數(shù)。這其中的一個例外就是構(gòu)造函數(shù),因為它違反了面向?qū)ο蟮母拍睢?/p>
關(guān)于這些的一個相似的現(xiàn)象是靜態(tài)對象,靜態(tài)對象的初始化是在程序的一開始階段就進(jìn)行的(在main()函數(shù)之前)。下面的代碼解釋了這種情況。
- MyClass static_object(88, 91);
- void bar()
- {
- if (static_object.count( ) > 14) {
- ...
- }
- }
在這個例子中,靜態(tài)變量在一開始的時候就被初始化。通常這些對象由兩部分構(gòu)成。第一部分是數(shù)據(jù)段,靜態(tài)變量被讀取到全局的數(shù)據(jù)段中。第二部分是靜態(tài)的初始化函數(shù),在main()函數(shù)之前被調(diào)用。我們發(fā)現(xiàn),一些編譯器沒有對初始化的可靠性進(jìn)行檢查。所以你得到的是未經(jīng)初始化的對象。解決的方案是,寫一個封裝函數(shù),將所有的靜態(tài)對象的引用都置于這個函數(shù)的調(diào)用中,上面的例子應(yīng)當(dāng)這樣改寫。
- static MyClass* static_object = 0;
- MyClass*
- getStaticObject()
- {
- if (!static_object)
- static_object =
- new MyClass(87, 92);
- return static_object;
- }
- void bar()
- {
- if (getStaticObject()->count( ) > 15)
- {
- ...
- }
- }
4、構(gòu)造函數(shù)不能成為虛函數(shù)
虛構(gòu)造函數(shù)意味著程序員在運行之前可以在不知道對象的準(zhǔn)確類型的情況下創(chuàng)建對象。虛構(gòu)造函數(shù)在C++中是不可能實現(xiàn)的。最通常遇到這種情況的地方是在對象上實現(xiàn)I/O的時候。即使足夠的類的內(nèi)部信息在文件中給出,也必須找到一種方法實例化相應(yīng)的類。然而,有經(jīng)驗的C++程序員會有其他的辦法來模擬虛構(gòu)造函數(shù)。
模擬虛函數(shù)需要在創(chuàng)建對象的時候指定調(diào)用的構(gòu)造函數(shù),標(biāo)準(zhǔn)的方法是調(diào)用虛的成員函數(shù)。很不幸,C++在語法上不支持虛構(gòu)造函數(shù)。為了繞過這個限制,一些現(xiàn)成的方法可以在運行時刻確定構(gòu)件的對象。這些等同于虛構(gòu)造函數(shù),但是這是C++中根本不存在的東西。
第一個方法是用switch或者if-else選擇語句來手動實現(xiàn)選擇。在下面的例子中,選擇是基于標(biāo)準(zhǔn)庫的type_info構(gòu)造,通過打開運行時刻類型信息支持。但是你也可以通過虛函數(shù)來實現(xiàn)RTTI
- class Base
- {
- public:
- virtual const char* get_type_id() const;
- staticBase* make_object
- (const char* type_name);
- };
- const char* Base::get_type_id() const
- {
- return typeid(*this).raw_name();
- }
- class Child1: public Base
- {
- };
- class Child2: public Base
- {
- };
- Base* Base::make_object(const char* type_name)
- {
- if (strcmp(type_name,
- typeid(Child1).raw_name()) == 0)
- return new Child1;
- else if (strcmp(type_name,typeid
- (Child2).raw_name()) == 0)
- return new Child2;
- else
- {
- throw exception
- ("unrecognized type name passed");
- return 0X00; // represent NULL
- }
- }
這一實現(xiàn)是非常直接的,它需要程序員在main_object中保存一個所有類的表。這就破壞了基類的封裝性,因為基類必須知道自己的子類。
一個更面向?qū)ο蟮姆椒惤鉀Q虛構(gòu)造函數(shù)叫做標(biāo)本實例。它的基本思想是程序中生成一些全局的實例。這些實例只再虛構(gòu)造函數(shù)的機制中存在:
- class Base
- {
- public:
- staticBase* make_object(const char* typename)
- {
- if (!exemplars.empty())
- {
- Base* end = *(exemplars.end());
- list<Base*>::iterator iter =
- exemplars.begin();
- while (*iter != end)
- {
- Base* e = *iter++;
- if (strcmp(typename,
- e->get_typename()) == 0)
- return e->clone();
- }
- }
- return 0X00 // Represent NULL;
- }
- virtual ~Base() { };
- virtual const char* get_typename() const
- {
- return typeid(*this).raw_name();
- }
- virtual Base* clone() const = 0;
- protected:
- static list<Base*> exemplars;
- };
- list<Base*> Base::exemplars;
- // T must be a concrete class
- // derived from Base, above
- template<class T>
- class exemplar: public T
- {
- public:
- exemplar()
- {
- exemplars.push_back(this);
- }
- ~exemplar()
- {
- exemplars.remove(this);
- }
- };
- class Child: public Base
- {
- public:
- ~Child()
- {
- }
- Base* clone() const
- {
- return new Child;
- }
- };
- exemplar<Child> Child_exemplar;
在這種設(shè)計中,程序員要創(chuàng)建一個類的時候要做的是創(chuàng)建一個相應(yīng)的exampler
#p#
5、創(chuàng)建一個缺省構(gòu)造函數(shù)
當(dāng)繼承被使用的時候,卻省構(gòu)造函數(shù)就會被調(diào)用。更明確地說,當(dāng)繼承層次的最晚層的類被構(gòu)造的時候,所有基類的構(gòu)造函數(shù)都在派生基類之前被調(diào)用,舉個例子來說,看下面的代碼:
- #include<iostream.h>
- class Base
- {
- int x;
- public :
- Base() : x(0) { } // The NULL constructor
- Base(int a) : x(a) { }
- };
- class alpha : virtual public Base
- {
- int y;
- public :
- alpha(int a) : Base(a), y(2) { }
- };
- class beta : virtual public Base
- {
- int z;
- public :
- beta(int a) : Base(a), z(3) { }
- };
- class gamma : public alpha, public beta
- {
- int w;
- public :
- gamma ( int a, int b) : alpha(a), beta(b), w(4) { }
- };
- main()
- {.....
- }
在這個例子中,我們沒有在gamma的頭文件中提供任何的初始化函數(shù)。編譯器會為基類使用缺省的構(gòu)造函數(shù)。但是因為你提供了一個構(gòu)造函數(shù),編譯器就不會提供任何缺省構(gòu)造函數(shù)。正如你看到的這段包含缺省構(gòu)造函數(shù)的代碼一樣,如果刪除其中的缺省構(gòu)造函數(shù),編譯就無法通過。
如果基類的構(gòu)造函數(shù)中引入一些副效應(yīng)的話,比如說打開文件或者申請內(nèi)存,這樣程序員就得確保中間基類沒有初始化虛基類。也就是,只有虛基類的構(gòu)造函數(shù)可以被調(diào)用。
虛基類的卻省構(gòu)造函數(shù)完成一些不需要任何依賴于派生類的參數(shù)的初始化。你加入一個init()函數(shù),然后再從虛基類的其他函數(shù)中調(diào)用它,或在其他類中的構(gòu)造函數(shù)里調(diào)用(你的確保它只調(diào)用了一次)。
6、不能取得構(gòu)造函數(shù)的地址
C++中,不能把構(gòu)造函數(shù)當(dāng)作函數(shù)指針來進(jìn)行傳遞,指向構(gòu)造函數(shù)的的指針也不可以直接傳遞。允許這些就可以通過調(diào)用指針來創(chuàng)建對象。一種達(dá)到這種目的的方法是借助于一個創(chuàng)建并返回新對象的靜態(tài)函數(shù)。指向這樣的函數(shù)的指針用于新對象需要的地方。下面是一個例子:
- class A
- {
- public:
- A( ); // cannot take the address of this
- // constructor directly
- static A* createA();
- // This function creates a new A object
- // on the heap and returns a pointer to it.
- // A pointer to this function can be passed
- // in lieu of a pointer to the constructor.
- };
這一方法設(shè)計簡單,只需要將抽象類置入頭文件即可。這給new留下了一個問題,因為準(zhǔn)確的類型必須是可見的。上面的靜態(tài)函數(shù)可以用來包裝隱藏子類。
7、位拷貝在動態(tài)申請內(nèi)存的類中不可行
C++中,如果沒有提供一個拷貝構(gòu)造函數(shù),編譯器會自動生成一個。生成的這個拷貝構(gòu)造函數(shù)對對象的實例進(jìn)行位拷貝。這對沒有指針成員的類來說沒什么,但是,對用了動態(tài)申請的類就不是這樣的了。為了澄清這一點,設(shè)想一個對象以值傳遞的方式傳入一個函數(shù),或者從函數(shù)中返回,對象是以為拷貝的方式復(fù)制。這種位拷貝對含有指向其他對象指針的類是沒有作用的。當(dāng)一個含有指針的類以值傳遞的方式傳入函數(shù)的時候,對象被復(fù)制,包括指針的地址,還有,新的對象的作用域是這個函數(shù)。在函數(shù)結(jié)束的時候,很不幸,析構(gòu)函數(shù)要破壞這個對象。因此,對象的指針被刪除了。這導(dǎo)致原來的對象的指針指向一塊空的內(nèi)存區(qū)域-一個錯誤。在函數(shù)返回的時候,也有類似的情況發(fā)生。
這個問題可以簡單的通過在類中定義一個含有內(nèi)存申請的拷貝構(gòu)造函數(shù)來解決,這種靠叫做深拷貝,是在堆中分配內(nèi)存給各個對象的。
8、編譯器可以隱式指定強制構(gòu)造函數(shù)
因為編譯器可以隱式選擇強制構(gòu)造函數(shù),你就失去了調(diào)用函數(shù)的選擇權(quán)。如果需要控制的話,不要聲明只有一個參數(shù)的構(gòu)造函數(shù),取而代之,定義helper函數(shù)來負(fù)責(zé)轉(zhuǎn)換,如下面的例子:
- #include <stdio.h>
- #include <stdlib.h>
- class Money
- {
- public:
- Money();
- // Define conversion functions that can only be
- // called explicitly.
- static Money Convert( char * ch )
- { return Money( ch ); }
- static Money Convert( double d )
- { return Money( d ); }
- void Print() { printf( "%f", _amount ); }
- private:
- Money( char *ch ) { _amount = atof( ch ); }
- Money( double d ) { _amount = d; }
- double _amount;
- };
- void main()
- {
- // Perform a conversion from type char *
- // to type Money.
- Money Account = Money::Convert( "57.29" );
- Account.Print();
- // Perform a conversion from type double to type
- // Money.
- Account = Money::Convert( 33.29 );
- Account.Print();
- }
在上面的代碼中,強制構(gòu)造函數(shù)定義為private而不可以被用來做類型轉(zhuǎn)換。然而,它可以被顯式的調(diào)用。因為轉(zhuǎn)換函數(shù)是靜態(tài)的,他們可以不用引用任何一個對象來完成調(diào)用。
總結(jié)
要澄清一點是,這里提到的都是我們所熟知的ANSI C++能夠接受的。許多編譯器都對ANSI C++進(jìn)行了自己的語法修訂。這些可能根據(jù)編譯器的不同而不同。很明顯,許多編譯器不能很好的處理這幾點。探索這幾點的緣故是引起編譯構(gòu)造的注意,也是在C++標(biāo)準(zhǔn)化的過程中移除一些瑕疵。
【編輯推薦】
- 程序員必看 c++筆試題匯總
- C++構(gòu)造函數(shù)如何進(jìn)行初始化
- 淺析C++中的C++構(gòu)造函數(shù)
- C#構(gòu)造函數(shù)概述
- 深度探討C++靜態(tài)構(gòu)造函數(shù)