• <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++
            日歷
            <2012年11月>
            28293031123
            45678910
            11121314151617
            18192021222324
            2526272829301
            2345678
            統計
            • 隨筆 - 92
            • 文章 - 4
            • 評論 - 4
            • 引用 - 0

            導航

            常用鏈接

            留言簿

            隨筆檔案

            文章檔案

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

             
              在C++中為什么輸入輸出流不能重載為類成員函數?

              假如說operator 《 ()這是一個成員函數,mealtime是一個類Time的私有成員,那么如我們看到的,如下一個輸出語句:cout《mealtime;將被編譯器處理為發送一條消息到cout,cout.operator《(mealtime);這表示operator 《必須是類ostream的一個成員,而不是類Time的一個成員。然而,即使能將這個新函數添加到標準ostream中,仍然不希望破壞標準的庫,因此operator 《必然是一個普通函數,這表示如下輸出語句:cout《mealtime將被編譯器看作函數調用operator《(cout,mealtime);這樣operator《()必須具有兩個形參,第一個是ostream類,第二個是Timer類。

              大部份的標準庫實現中,對ostream,istream類體系采用了構造函數保護繼承的方式……致使即使以繼承的方式來擴展流類,也會在對象實例化時遭遇阻礙……

              另一方面,標準庫中的流類,其插入符函數沒有聲明為虛函數,因此子類不能對其實現進行覆蓋,所以也使成員函數重載遭遇到實質的困難……

              總的來說,C++標準I/O庫非常繁雜且難,其實現思想很多都與常規的OOP有所出入……在使用的時候要謹慎,并最好遵從慣例……

              為什么C++賦值運算符不能被繼承?

              1,每一個類對象實例在創建的時候,如果用戶沒有定義“賦值運算符重載函數”,那么,編譯器會自動生成一個隱含和默認的“賦值運算符重載函數”。所以,B1的實際上的聲明應該類似于下面這種情況:

              class A1

              {

              public:

              int operator=(int a)

              {

              return 8;

              }

              int operator+(int a)

              {

              return 9;

              }

              };

              class B1 : public A1

              {

              public:

              B1& operator =(const B1& robj); // 注意這一行是編譯器添加的

              int operator-(int a)

              {

              return 7;

              }

              };

              2,C++標準規定:如果派生類中聲明的成員與基類的成員同名,那么,基類的成員會被覆蓋,哪怕基類的成員與派生類的成員的數據類型和參數個數都完全不同。顯然,B1中的賦值運算符函數名operator =和基類A1中的operator =同名,所以,A1中的賦值運算符函數int operator=(int a);被B1中的隱含的賦值運算符函數B1& operator =(const B1& robj);所覆蓋。 A1中的int operator=(int a);函數無法被B1對象訪問。 www.liuhebao.com

              3,程序中語句v = 2實際上相當于v.operator =(2);,但是A1中的int operator=(int a);已經被覆蓋,無法訪問。而B1中默認的B1& operator =(const B1& robj);函數又與參數2的整數類型不相符,無法調用。

              4,為了確認B1中默認的B1& operator =(const B1& robj);函數的存在性,可以用以下代碼驗證:

              B1 b;

              B1 v;

              v = b; // OK, 相當于調用v.operator =(b);STA

              5,所以,“賦值運算符重載函數”不是不能被派生類繼承,而是被派生類的默認“賦值運算符重載函數”給覆蓋了。

              這就是C++賦值運算符重載函數不能被派生類繼承的真實原因!

              關于本帖問題正確性的解釋

              C++程序員的必讀經典《Effective C++》這么說:

              條款45: 弄清C++在幕后為你所寫、所調用的函數

              一個空類什么時候不是空類? ---- 當C++編譯器通過它的時候。如果你沒有聲明下列函數,體貼的編譯器會聲明它自己的版本。這些函數是:一個拷貝構造函數,一個賦值運算符,一個析構函數,一對取址運算符。另外,如果你沒有聲明任何構造函數,它也將為你聲明一個缺省構造函數。所有這些函數都是公有的。換句話說,如果你這么寫:

              class Empty{};

              和你這么寫是一樣的:

              class Empty {

              public:

              Empty(); // 缺省構造函數

              Empty(const Empty& rhs); // 拷貝構造函數

              ~Empty(); // 析構函數 ---- 是否

              // 為虛函數看下文說明

              Empty&

              operator=(const Empty& rhs); // 賦值運算符

              Empty* operator&(); // 取址運算符

              const Empty* operator&() const;

              };

              但是Effective C++依然不能作為最后的判決。讓我們從C++的“憲法”中尋找答案…

              ISO/IEC 14882是C++的國際標準。該標準于1998年9月1日通過并且定案。當然,這個標準已經不是最新標準了,但這個標準卻是目前最被廣泛支持的C++標準。所以,我一向稱之為C++的“憲法”。

              C++“憲法”第12章 Special Member Functions (第185頁)開宗明義:

              The default constructor, copy constructor and copy assignment operator, and destructor are special member functions. The implementation will implicitly declare these member functions for a class type when the program does not explicitly declare them, except as noted in 12.1. The implementation will implicitly define then if they are used, as specified in 12.1, 12.4 and 12.8. Programs shall not define implicitly-declared special member functions. Programs may explicitly refer to implicitly declared special member functions.

              譯文:

              缺省構造函數,拷貝構造函數,拷貝賦值函數,以及析構函數這四種成員函數被稱作特殊的成員函數。如果用戶程序沒有顯式地聲明這些特殊的成員函數,那么編譯器實現將隱式地聲明它們。12.1中有特別解釋的例外。如果用戶程序調用了這些特殊的成員函數,那么編譯器就會定義這些特殊的成員函數,在12.1,12.4,12.8中分別規定了編譯器對這些函數的定義方式。用戶程序不能定義隱式聲明的特殊成員函數。用戶程序可以顯式地調用隱式聲明的特殊成員函數。

              譯注:

              根據C++標準的規定:

              聲明(Declare)代表頭文件中的那部分代碼,比如下面就是一個聲明:

              class A

              {

              public:

              A();

              }

              定義(Define)代表源文件中的代碼,比如下面就是一個定義:

              A::A()

              {}

              綜上所述,可知,第一個說法是正確的。

              關于第二個說法的正確性,可參見C++“憲法”3.3.7 Name Hiding (第28頁)(由于我手上的C++“憲法”是掃描版,無法直接拷貝文字,且文字較多,懶得輸入了。)

              第3,4,5點說法都是常識性的知識,可以直接驗證。
            posted on 2012-11-26 18:14 HAOSOLA 閱讀(249) 評論(0)  編輯 收藏 引用
             
            Copyright © HAOSOLA Powered by: 博客園 模板提供:滬江博客
            PK10開獎 PK10開獎
            国产精自产拍久久久久久蜜| 亚洲精品无码久久千人斩| 91精品国产色综久久| 欧美大战日韩91综合一区婷婷久久青草| 久久久久久久尹人综合网亚洲 | 日韩人妻无码精品久久久不卡 | 久久夜色tv网站| 久久精品国产99久久香蕉| 麻豆精品久久久久久久99蜜桃 | 99久久精品国产一区二区三区| 久久成人国产精品一区二区| 久久久久亚洲AV无码观看| 久久国产精品-久久精品| 精品久久久一二三区| 亚洲天堂久久精品| 77777亚洲午夜久久多喷| 国产综合精品久久亚洲| 久久av无码专区亚洲av桃花岛| 久久婷婷人人澡人人| 久久最近最新中文字幕大全| 亚洲国产美女精品久久久久∴| 精品无码久久久久久国产| 久久99精品国产一区二区三区| 国产成人无码精品久久久性色 | 99久久精品免费看国产一区二区三区| 九九久久99综合一区二区| 亚洲va中文字幕无码久久| 亚洲精品乱码久久久久久蜜桃| 久久久九九有精品国产| 国内精品久久九九国产精品| 久久久久亚洲精品无码蜜桃| 亚洲精品无码久久久久去q| 亚洲天堂久久久| 亚洲午夜无码久久久久小说| 欧美精品丝袜久久久中文字幕| 久久精品二区| 一本大道久久香蕉成人网| 人妻无码αv中文字幕久久琪琪布 人妻无码精品久久亚瑟影视 | 99久久99久久| 中文字幕亚洲综合久久2| 国产精品久久久福利|