搜索
熱搜: 活動 交友 discuz
查看: 3551|回復: 0
打印 上一主題 下一主題

[教學] ■C++ Primer p904

[複製鏈接]
跳轉到指定樓層
1#
發表於 2007-9-4 09:10:16 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
■C++ Primer p904
主題:using declaration 可將 base class 內任何一個具名的 member
      (條件是 accessible)放進 derived class scope 內。
測試結果:VC6[x]  BCB4[o]  G++[x]
          但如果將下例的 using declaration 移到 Shy::mumble() 之前,則 VC6[o]
實例:

#001 #include <iostream>
#002 #include <string>
#003 using namespace std;
#004
#005 class Diffident {
#006 public:
#007     void mumble (int softnes)
#008     { cout << "Diffident::mumble" << endl; };
#009 };
#010
#011 class Shy : public Diffident {
#012 public:
#013     void mumble(string whatYaSay)
#014     { cout << "Shy::mumble" << endl; };
#015     using Diffident::mumble;
#016 };
#017
#018 void main()
#019 {
#020 Diffident d;
#021 Shy s;
#022 string str("jjhou");
#023
#024   d.mumble(5);     // Diffident::mumble
#025   s.mumble(5);     // should be "Diffident::mumble"
#026   s.mumble(str);   // Shy::mumble
#027 }


■C++ Primer p940
主題:設計 "virtual" new operator(亦即 clone)時所需
      的一個技術:如果虛擬函式的 base instance 傳回
      'A' class type(或為指標,或為 reference),那麼
      虛擬函式的 base instance 可以傳回 'A' type 或 'A'
      的 publicly derived class(或為指標,或為 reference)
測試結果:VC6[x]  BCB4[o]  G++[o]
實例:

#001 class Query {
#002 public:
#003   virtual Query* clone() = 0;
#004 };
#005
#006 class NameQuery : public Query {
#007 public:
#008   virtual NameQuery* clone() { return new NameQuery(*this); }
#009   // VC6 error C2555: 'NameQuery::clone' : overriding virtual function
#010   //   differs from 'Query::clone' only by return type or calling convention
#011   //   see declaration of 'Query'
#012 };
#013
#014 void main()
#015 {
#016   Query* pq  = new NameQuery();
#017   Query* pq2 = pq->clone();
#018
#019   NameQuery* pnq  = new NameQuery();
#020   NameQuery* pnq2 = pnq->clone();
#021 }



■C++ Primer p998
註:2001.08.22 新增
主題:虛擬繼承中的 base class ctor invocation 問題。
測試結果:
實例:gcc291[o], vc6[x], cb4[x], cb5[x]

#0001 // gcc[o], vc6[x], cb4[x], cb5[x]
#0002
#0003 #include <iostream>
#0004 #include <string>
#0005 using namespace std;
#0006
#0007 class ZooAnimal {
#0008 public:
#0009     ZooAnimal( string name, bool onExhibit, string fam_name )
#0010                : _name( name ),
#0011                  _onExhibit( onExhibit),
#0012                  _fam_name( fam_name )
#0013     {}
#0014
#0015     virtual ~ZooAnimal() { };
#0016     string name() const { return _name; };
#0017     string family_name() const { return _fam_name; }
#0018     // ...
#0019
#0020 protected:
#0021     bool   _onExhibit;
#0022     string _name;
#0023     string _fam_name;
#0024     // ...
#0025 };
#0026
#0027 class Bear : public virtual ZooAnimal {
#0028 public:
#0029     enum DanceType {
#0030          two_left_feet, macarena, fandango, waltz };
#0031
#0032     Bear( string name, bool onExhibit=true )
#0033         : ZooAnimal( name, onExhibit, "Bear" ),
#0034           _dance( two_left_feet )
#0035     {}
#0036
#0037     void dance( DanceType );
#0038     // ...
#0039
#0040 protected:
#0041     DanceType _dance;
#0042     // ...
#0043 };
#0044
#0045
#0046 class Raccoon : public virtual ZooAnimal {
#0047 public:
#0048     Raccoon( string name, bool onExhibit=true )
#0049            : ZooAnimal( name, onExhibit, "Raccoon" ),
#0050              _pettable( false )
#0051     {}
#0052
#0053     bool pettable() const { return _pettable;   }
#0054     void pettable( bool petval ) { _pettable = petval; }
#0055     // ...
#0056
#0057 protected:
#0058     bool _pettable;
#0059     // ...
#0060 };
#0061
#0062
#0063 class Panda : public Bear,
#0064               public Raccoon {
#0065 public:
#0066     Panda( string name, bool onExhibit=true );
#0067     bool sleeping() const { return _sleeping; }
#0068     void sleeping( bool newval ) { _sleeping = newval; }
#0069     // ...
#0070
#0071 protected:
#0072     bool _sleeping;
#0073     // ...
#0074 };
#0075
#0076 Panda::Panda( string name, bool onExhibit=true )
#0077       : ZooAnimal( name, onExhibit, "Panda" ),    // <<-- note
#0078         Bear( name, onExhibit ),
#0079         Raccoon( name, onExhibit ),
#0080         _sleeping( false )
#0081 {}
#0082
#0083
#0084 int main()
#0085 {
#0086   Bear winnie("Pooh");
#0087   Raccoon meeko("meeko");
#0088   Panda yolo("yolo");
#0089 }

注意:如果將 #0076 的 =true 去除,則 gcc291[o], vc6[o], cb4[o], cb5[o]




■C++ Primer p1090
主題:friend operator<<
測試結果:VC6[x]  BCB4[o]  G++[o]
注意:如果使用 <iostream.h> 而不是 <iostream>,在 VC6 中
      運用 friend 就比較沒有問題。但如果這麼做的話,由於下例
      用到 <string>,一定得 using namespace std; 而這在 VC6 中似乎
      導至暗中含入 <iostream>,於是與 <iostream.h> 起衝突。總之,
      挖東補西,很煩。VC6 在這主題上表現不佳。
實例:

#001 #include <iostream>
#002 #include <string>
#003 using namespace std;
#004
#005 class WordCount {
#006     friend ostream& operator<<(ostream&, const WordCount&);
#007 public:
#008     WordCount( string& word, int cnt=1 )
#009     : _word(word), _occurs(cnt)
#010     { };
#011 private:
#012     string _word;
#013     int _occurs;
#014 };
#015
#016 ostream& operator <<( ostream& os, const WordCount& wd )
#017 {    // format: <occurs> word
#018      os << "< " << wd._occurs << " > " << wd._word;  // VC error!
#019      return os;
#020 }
#021
#022 void main()
#023 {
#024   string s1("Hello");
#025   string s2("jjhou");
#026   WordCount w1(s1, 5);
#027   WordCount w2(s2, 7);
#028   cout << w1 << endl;   // < 5 > Hello
#029   cout << w2 << endl;   // < 7 > jjhou
#030 }


■C++ Primer p1126 下
主題:list<T> 的 object initialization
測試結果:VC6[o]  BCB4[x](有瑕疵) G++[o]
實例:
    以下這行可通過 VC6 和 G++
    list<int> ilist_result(ilist.size());

    為了在 BCB4 中通過,需改為:
    int i = ilist.size();
    list<int> ilist_result(i, -1);


■C++ Primer p1156~p1157
主題:generic algorithms max() 和 min()
測試結果:VC6 所附的 STL 竟未支援 max 和 min 這兩個 generic algorithms。
聯想:試看這個程式:

(01) #include <iostream>
(02) #include <string>
(03) using namespace std;
(04)
(05) template <typename T>
(06) T min( T v1, T v2)       // <-- note
(07) {
(08)    return (v1 < v2 ? v1 : v2);
(09) }
(10)
(11) class Rect {
(12)   friend ostream& operator<<(ostream& os, Rect& r);
(13) public:
(14)   Rect(int i) : _i(i) {  }
(15)   bool operator<(Rect& rhs)
(16)     { return (this->_i < rhs._i ? true : false); }
(17) private:
(18)   int _i;
(19) };
(20)
(21) ostream& operator<<(ostream& os, Rect& r)
(22) {
(23)    os << r._i;
(24)    return os;
(25) }
(26)
(27) void main()
(28) {
(29)    cout << min( 17, 15) << endl;           // 15
(30)    cout << min(13.5, 13.57) << endl;       // 13.5
(31)    cout << min('a', 'e') << endl;          // a
(32)    cout << min("jjhou", "allan") << endl;  // allan
(33)
(34)    Rect r1(6), r2(3), r3(9);
(35)    cout << r1 << r2 << r3 << endl;         // 639
(36)    cout << min(r1, r2) << endl;            // 3
(37) }

檢討:
一 此程式在 VC6 中失敗,但如果改為 #include<iostream.h>
並移除 using namespace std; 則成功,這是 VC6 的 bug!
(見先前對 friend 的討論,C++ Primer p1090)

二 此程式在 BCB4 中失敗,錯誤訊息如下:
Error E2094 T1.CPP 36: 'operator<<' not implemented in type
'ostream' for arguments of type 'Rect' in function main()

這是因為我們的 template function min() 和 BCB4 提供之 STL 中
的 gemeric algorithm min() 名稱一樣。程式中喚起的其實是 STL 的
gemeric algorithm min(),而其 parameter list 內對於 parameters
的 constness 的要求,導至編譯器在進行 template argument deduction 時,
不接受我所提供的 Rect。只要將程式中的 min() 改為 mymin(),並將
(12) 和 (21) 的最後一個參數型別改為 const Rect&,即可。

注意:有時候雖然你並未明白含入某些 header files,或是你並未明白
使用 using namespace std; 編譯器卻會暗自加上。前者是由於 header files
一個含入一個…導至,後者請看 BCB4 的每一個 header files 的最後面,
幾乎都有這一行:

#ifndef __USING_STD_NAMES__
  using namespace std;
#endif

三 此程式在 G++ 中獲得警告訊息如下:
t1.cpp:36: warning: initialization of non-const reference
'class Rect &' from rvalue 'Rect'
t1.cpp:22: warning: in passing argument 2 of
'operator <<(ostream &, Rect &)'

其道理與修改方法,和上述二相同:將 min() 改名為 mymin() 即可。

心得:程式中不要出現任何命名與 C++ standard library 內的 components 同名。


■C++ Primer p1169
主題:generic algorithms random_shuffle()
測試結果:G++ 所附的 STL 對 random_shuffle() 的支援有問題


■Effective C++ 2/e  p70
主題:如果 base class 的 operator= 係由編譯器產生,亦即所謂
      default operator=,某些編譯器會拒絕讓你明白喚起 base class operator=,
      這不是好現象。
測試結果:VC6[o]  BCB4[x]  G++[o] (BCB4 表現不佳,拒絕我們喚起上述 operator=)
實例:

#001 class Base {
#002 ...
#003   // no defined operator=
#004 };
#005
#006 class Derived : public Base {
#007 ...
#008   Derived& operator=(const Derived& rhs);
#009 };
#010
#011 Derived& Derived::operator=(const Derived& rhs)
#012 {
#013   if (this == &rhs) return *this;
#014
#015   // explicitly invoke Base operator=。VC6[o]  BCB4[x]  G++[o]
#016   Base::operator=(rhs);
#017   ...
#018 }



以下是 2001/03/03 新增:

■C++ Primer p688
主題:local class
測試結果:VC6 不符 C++ Standard

(01) // VC6[x]  CB4[x]  G++[x]
(02)
(03) int a, val;
(04)
(05) void foo( int val )
(06) {
(07)     static int si;
(08)     enum Loc { a = 1024, b };
(09)     class Bar {
(10)     public:
(11)         Loc locVal; // ok;
(12)         int barVal;
(13)         void fooBar( Loc l = a ) { // ok: Loc::a
(14)             barVal = val;    // error: local object
(15)             barVal = ::val;  // ok: global object
(16)             barVal = si;     // ok: static local object
(17)             locVal = b;      // ok: enumerator
(18)         }
(19)     };
(20)     // ...
(21) }
(22)
(23) int main()
(24) {
(25)   foo(5);
(26) }

編譯結果

[VC6]:
..\688.cpp(16) : error C2065: 'si' : undeclared identifier
..\688.cpp(17) : error C2065: 'b' : undeclared identifier
..\688.cpp(17) : error C2440: '=' : cannot convert from 'int' to
                                    'enum foo::Loc'
  Conversion to enumeration type requires an explicit cast (static_cast,
C-style cast or function-style cast)
結論:VC6 不符合 C++ standard.

[BCB4]:
Error E2451 ..\688.CPP 14: Undefined symbol 'val' in function Bar::fooBar(Loc)
結論:BCB4 符合 C++ standard.

[GCC]:
..\\688.cpp: In method `void foo(int)::Bar::fooBar(enum foo(int)::Loc = a)':
..\\688.cpp:14: use of parameter from containing function
..\\688.cpp:6:   `int val' declared here
結論:GCC 符合 C++ standard.
您需要登錄後才可以回帖 登錄 | 註冊

本版積分規則

本論壇為非營利之網路平台,所有文章內容均為網友自行發表,不代表論壇立場!若涉及侵權、違法等情事,請告知版主處理。


Page Rank Check

廣告刊登  |   交換連結  |   贊助我們  |   服務條款  |   免責聲明  |   客服中心  |   中央分站

手機版|中央論壇

GMT+8, 2026-8-2 15:14 , Processed in 0.461853 second(s), 16 queries .

Powered by Discuz!

© 2005-2015 Copyrights. Set by YIDAS

快速回復 返回頂部 返回列表