|
|
■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. |
|