• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            來吧,朋友!

            為C++瘋狂

            [轉帖] c++中的explicit關鍵字

             c++中的explicit關鍵字用來修飾類的構造函數,表明該構造函數是顯式的,既然有"顯式"那么必然就有"隱式",那么什么是顯示而什么又是隱式的呢?

            如果c++類的構造函數有一個參數,那么在編譯的時候就會有一個缺省的轉換操作:將該構造函數對應數據類型的數據轉換為該類對象,如下面所示:
            class MyClass
            {
            public:
            MyClass( int num );
            }
            ....
            MyClass obj = 10; //ok,convert int to MyClass
            在上面的代碼中編譯器自動將整型轉換為MyClass類對象,實際上等同于下面的操作:
            MyClass temp(10);
            MyClass obj = temp;
            上面的所有的操作即是所謂的"隱式轉換"。

            如果要避免這種自動轉換的功能,我們該怎么做呢?嘿嘿這就是關鍵字explicit的作用了,將類的構造函數聲明為"顯示",也就是在聲明構造函數的時候前面添加上explicit即可,這樣就可以防止這種自動的轉換操作,如果我們修改上面的MyClass類的構造函數為顯示的,那么下面的代碼就不能夠編譯通過了,如下所示:
            class MyClass
            {
            public:
            explicit MyClass( int num );
            }
            ....
            MyClass obj = 10; //err,can't non-explict convert

            class isbn_mismatch:public std::logic_error{
            public:
            explicit isbn_missmatch(const std::string &s):std:logic_error(s){}
            isbn_mismatch(const std::string &s,const std::string &lhs,const std::string &rhs):
            std::logic_error(s),left(lhs),right(rhs){}
            const std::string left,right;
            virtual ~isbn_mismatch() throw(){}
            };


            Sales_item& operator+(const Sales_item &lhs,const Sales_item rhs)
            {
            if(!lhs.same_isbn(rhs))
               throw isbn_mismatch("isbn missmatch",lhs.book(),rhs.book());
            Sales_item ret(lhs);
            ret+rhs;
            return ret;
            }


            Sales_item item1,item2,sum;
            while(cin>>item1>>item2)
            {
            try{
               sun=item1+item2;
            }catch(const isbn_mismatch &e)
            {
               cerr<<e.what()<<"left isbn is:"<<e.left<<"right isbn is:"<<e.right<<endl;
            }
            }

            用于用戶自定義類型的構造函數,指定它是默認的構造函數,不可用于轉換構造函數.因為構造函數有三種:1拷貝構造函數2轉換構造函數3一般的構造函數(我自己的術語^_^)
            另:如果一個類或結構存在多個構造函數時,explicit 修飾的那個構造函數就是默認的

            class isbn_mismatch:public std::logic_error{
            public:
            explicit isbn_missmatch(const std::string &s):std:logic_error(s){}
            isbn_mismatch(const std::string &s,const std::string &lhs,const std::string &rhs):
            std::logic_error(s),left(lhs),right(rhs){}
            const std::string left,right;
            virtual ~isbn_mismatch() throw(){}
            };


            Sales_item& operator+(const Sales_item &lhs,const Sales_item rhs)
            {
            if(!lhs.same_isbn(rhs))
               throw isbn_mismatch("isbn missmatch",lhs.book(),rhs.book());
            Sales_item ret(lhs);
            ret+rhs;
            return ret;
            }


            Sales_item item1,item2,sum;
            while(cin>>item1>>item2)
            {
            try{
               sun=item1+item2;
            }catch(const isbn_mismatch &e)
            {
               cerr<<e.what()<<"left isbn is:"<<e.left<<"right isbn is:"<<e.right<<endl;
            }
            }

             

            這個 《ANSI/ISO C++ Professional Programmer's Handbook 》是這樣說的

            explicit Constructors
            A constructor that takes a single argument is, by default, an implicit conversion operator, which converts its argument to
            an object of its class (see also Chapter 3, "Operator Overloading"). Examine the following concrete example:
            class string
            {
            private:
            int size;
            int capacity;
            char *buff;
            public:
            string();
            string(int size); // constructor and implicit conversion operator
            string(const char *); // constructor and implicit conversion operator
            ~string();
            };
            Class string has three constructors: a default constructor, a constructor that takes int, and a constructor that
            constructs a string from const char *. The second constructor is used to create an empty string object with an
            initial preallocated buffer at the specified size. However, in the case of class string, the automatic conversion is
            dubious. Converting an int into a string object doesn't make sense, although this is exactly what this constructor does.

            Consider the following:
            int main()
            {
            string s = "hello"; //OK, convert a C-string into a string object
            int ns = 0;
            s = 1; // 1 oops, programmer intended to write ns = 1,
            }
            In the expression s= 1;, the programmer simply mistyped the name of the variable ns, typing s instead. Normally,
            the compiler detects the incompatible types and issues an error message. However, before ruling it out, the compiler first
            searches for a user-defined conversion that allows this expression; indeed, it finds the constructor that takes int.
            Consequently, the compiler interprets the expression s= 1; as if the programmer had written
            s = string(1);
            You might encounter a similar problem when calling a function that takes a string argument. The following example
            can either be a cryptic coding style or simply a programmer's typographical error. However, due to the implicit
            conversion constructor of class string, it will pass unnoticed:
            int f(string s);
            int main()
            {
            f(1); // without a an explicit constructor,
            //this call is expanded into: f ( string(1) );
            //was that intentional or merely a programmer's typo?
            }
            'In order to avoid such implicit conversions, a constructor that takes one argument needs to be declared explicit:
            class string
            {
            //...
            public:
            explicit string(int size); // block implicit conversion
            string(const char *); //implicit conversion
            ~string();
            };
            An explicit constructor does not behave as an implicit conversion operator, which enables the compiler to catch the
            typographical error this time:
            int main()
            {
            string s = "hello"; //OK, convert a C-string into a string object
            int ns = 0;
            s = 1; // compile time error ; this time the compiler catches the typo
            }
            Why aren't all constructors automatically declared explicit? Under some conditions, the automatic type conversion is
            useful and well behaved. A good example of this is the third constructor of string:
            string(const char *);

            The implicit type conversion of const char * to a string object enables its users to write the following:
            string s;
            s = "Hello";
            The compiler implicitly transforms this into
            string s;
            //pseudo C++ code:
            s = string ("Hello"); //create a temporary and assign it to s
            On the other hand, if you declare this constructor explicit, you have to use explicit type conversion:
            class string
            {
            //...
            public:
            explicit string(const char *);
            };
            int main()
            {
            string s;
            s = string("Hello"); //explicit conversion now required
            return 0;
            }
            Extensive amounts of legacy C++ code rely on the implicit conversion of constructors. The C++ Standardization
            committee was aware of that. In order to not make existing code break, the implicit conversion was retained. However, a
            new keyword, explicit, was introduced to the languageto enable the programmer to block the implicit conversion
            when it is undesirable. As a rule, a constructor that can be invoked with a single argument needs to be declared
            explicit. When the implicit type conversion is intentional and well behaved, the constructor can be used as an
            implicit conversion operator.

            網上找的講的最好的貼:

            C++ 中 explicit 關鍵字的作用
            在 C++ 中, 如果一個類有只有一個參數的構造函數,C++ 允許一種特殊的聲明類變量的方式。在這種情況下,可以直接將一個對應于構造函數參數類型的數據直接賦值給類變量,編譯器在編譯時會自動進行類型轉換,將對應于構造函數參數類型的數據轉換為類的對象。 如果在構造函數前加上 explicit 修飾詞, 則會禁止這種自動轉換,在這種情況下,即使將對應于構造函數參數類型的數據直接賦值給類變量,編譯器也會報錯。

            下面以具體實例來說明。

            建立people.cpp 文件,然后輸入下列內容:

            class People
            {
            public:
            int age;
            explicit People (int a)
             {
              age=a;
             }
            };
            void foo ( void )
            {
             People p1(10);  //方式一
             People* p_p2=new People(10); //方式二
             People p3=10; //方式三
            }
            這段 C++ 程序定義了一個類 people ,包含一個構造函數, 這個構造函數只包含一個整形參數 a ,可用于在構造類時初始化 age 變量。

            然后定義了一個函數foo,在這個函數中我們用三種方式分別創建了三個10歲的“人”。第一種是最一般的類變量聲明方式。第二種方式其實是聲明了一個people類的指針變量,然后在堆中動態創建了一個people實例,并把這個實例的地址賦值給了p_p2。第三種方式就是我們所說的特殊方式,為什么說特殊呢?我們都知道,C/C++是一種強類型語言,不同的數據類型是不能隨意轉換的,如果要進行類型轉換,必須進行顯式強制類型轉換,而這里,沒有進行任何顯式的轉換,直接將一個整型數據賦值給了類變量p3。

            因此,可以說,這里進行了一次隱式類型轉換,編譯器自動將對應于構造函數參數類型的數據轉換為了該類的對象,因此方式三經編譯器自動轉換后和方式一最終的實現方式是一樣的。

            不相信? 耳聽為虛,眼見為實,讓我們看看底層的實現方式。

            為了更容易比較方式一和方式三的實現方式,我們對上面的代碼作一點修改,去除方式二:

            void foo ( void )
            {
             People p1(10);  //方式一
             People p3=10; //方式三
            }
            去除方式二的原因是方式二是在堆上動態創建類實例,因此會有一些額外代碼影響分析。修改完成后,用下列命令編譯 people.cpp

            $ gcc -S people.cpp

            "-S"選項是GCC輸出匯編代碼。命令執行后,默認生成people.s。 關鍵部分內容如下:

            .globl _Z3foov
            .type _Z3foov, @function
            _Z3foov:
            .LFB5:
             pushl %ebp
            .LCFI2:
             movl %esp, %ebp
            .LCFI3:
             subl $24, %esp
            .LCFI4:
             movl $10, 4(%esp)
             leal -4(%ebp), %eax
             movl %eax, (%esp)
             call _ZN6PeopleC1Ei
             movl $10, 4(%esp)
             leal -8(%ebp), %eax
             movl %eax, (%esp)
             call _ZN6PeopleC1Ei
             leave
             ret

            看“.LCFI4” 行后面的東西,1-4行和5-8行幾乎一模一樣,1-4行即為方式一的匯編代碼,5-8即為方式三的匯編代碼。 細心的你可能發現2和6行有所不同,一個是 -4(%ebp) 而另一個一個是 -8(%ebp) ,這分別為類變量P1和P3的地址。

            對于不可隨意進行類型轉換的強類型語言C/C++來說, 這可以說是C++的一個特性。哦,今天好像不是要說C++的特性,而是要知道explicit關鍵字的作用?

            explicit關鍵字到底是什么作用呢? 它的作用就是禁止這個特性。如文章一開始而言,凡是用explicit關鍵字修飾的構造函數,編譯時就不會進行自動轉換,而會報錯。

            讓我們看看吧! 修改代碼:

            class People
            {
            public:
            int age;
            explicit People (int a)
             {
              age=a;
             }
            };
            然后再編譯:
            $ gcc -S people.cpp
            編譯器立馬報錯:
            people.cpp: In function ‘void foo()’:
            people.cpp:23: 錯誤:請求從 ‘int’ 轉換到非標量類型 ‘People’

            posted on 2009-07-24 16:49 yanghaibao 閱讀(221) 評論(0)  編輯 收藏 引用

            導航

            <2009年7月>
            2829301234
            567891011
            12131415161718
            19202122232425
            2627282930311
            2345678

            統計

            常用鏈接

            留言簿

            隨筆分類

            隨筆檔案

            文章檔案

            收藏夾

            Good blogs

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            青青青青久久精品国产 | 91久久婷婷国产综合精品青草| 久久综合综合久久狠狠狠97色88| 国产精品久久新婚兰兰| 久久天堂AV综合合色蜜桃网| 亚洲美日韩Av中文字幕无码久久久妻妇| 国产综合久久久久| 久久一日本道色综合久久| 99久久精品免费看国产一区二区三区| 久久综合久久鬼色| 久久久久女教师免费一区| 久久精品国产清自在天天线| 久久精品国产国产精品四凭| 久久天天躁狠狠躁夜夜av浪潮| 久久AAAA片一区二区| 久久午夜福利电影| 日产久久强奸免费的看| 2021国产精品午夜久久| 人妻无码精品久久亚瑟影视 | 久久国产精品免费| 久久综合五月丁香久久激情| 伊人久久成人成综合网222| 亚洲美日韩Av中文字幕无码久久久妻妇 | 亚洲国产日韩综合久久精品| 热99RE久久精品这里都是精品免费 | 久久精品国产亚洲av麻豆蜜芽| 青青草原综合久久大伊人| 久久久久亚洲av无码专区喷水| 色综合久久久久| 精品久久久久久无码不卡| 久久99亚洲网美利坚合众国| 日本精品久久久久中文字幕8| 久久国产精品无码网站| 狠狠精品久久久无码中文字幕| 久久久久久久久无码精品亚洲日韩 | 激情综合色综合久久综合| 亚洲国产精品无码久久久久久曰| 伊人久久无码中文字幕| 热久久国产精品| 久久久久亚洲AV成人片| 久久久久亚洲AV无码专区网站|