Operator Overloading
下面的代码是一段运算符重载代码:
- class CVeryLong
- {
- public:
- // default contructor inits member variables to zero
- CVeryLong(){ m_lHigh = m_lLow = 0; }
- // initialization constructor sets member variables to a value
- CVeryLong( long lHigh, long lLow ){ m_lHigh = lHigh; m_lLow = lLow; }
- virtual ~CVeryLong(){}; // destructor
- void SetHighValue( long lValue ){ m_lHigh = lValue; }
- long GetHighValue(){ return m_lHigh; }
- void SetLowValue( long lValue ){ m_lLow = lValue; }
- long GetLowValue(){ return m_lLow; }
- BOOL operator < ( CVeryLong& refValue ) // less than operator
- {
- if ( m_lHigh < refValue.GetHighValue()) return TRUE;
- else if ( m_lHigh > refValue.GetHighValue()) return FALSE;
- else if ( m_lLow < refValue.GetLowValue()) return TRUE;
- else return FALSE; // >=
- }
- BOOL operator > ( CVeryLong& refValue ) // greater than operator
- {
- if ( m_lHigh > refValue.GetHighValue()) return TRUE;
- else if ( m_lHigh < refValue.GetHighValue()) return FALSE;
- else if ( m_lLow > refValue.GetLowValue()) return TRUE;
- else return FALSE; // <=
- }
- BOOL operator == ( CVeryLong& refValue ) // equivalence operator
- {
- return m_lHigh == refValue.GetHighValue()
- && m_lLow == refValue.GetLowValue();
- }
- private:
- long m_lLow;
- long m_lHigh;
- };
CVeryLong 类有两个long私有变量,能够显示一个64位整型数。在这个类中,我们重载了小于号(<),大于号(>),等于号(=),使得64位整数类可以进行比较运算。显然,这个类是不完整的,因为还有很多数学运算符没重载。下面的代码简单使用我们的新类:
- {
- CString csText;
- CVeryLong vl1( 1, 2 ), vl2( 1, 3 ), vl3;
- cout << "vl1 is (1, 2)" << endl;
- cout << "vl2 is (1, 3)" << endl;
- cout << "vl3 is (1, 2)" << endl;
- csText = "vl1 < vl2 is ";
- csText += vl1 < vl2 ? "true" : "false";
- cout << (LPCTSTR)csText << endl;
- csText = "vl1 > vl2 is ";
- csText += vl1 > vl2 ? "true" : "false";
- cout << (LPCTSTR)csText << endl;
- csText = "vl1 = = vl2 is ";
- csText += vl1 == vl2 ? "true" : "false";
- cout << (LPCTSTR)csText << endl;
- csText = "vl1 < vl3 is ";
- csText += vl1 < vl3 ? "true" : "false";
- cout << (LPCTSTR)csText << endl;
- csText = "vl1 > vl3 is ";
- csText += vl1 > vl3 ? "true" : "false";
- cout << (LPCTSTR)csText << endl;
- csText = "vl1 = = vl3 is ";
- csText += vl1 == vl3 ? "true" : "false";
- cout << (LPCTSTR)csText << endl;
- }
运行结果:
- vl1 is (1, 2)
- vl2 is (1, 3)
- vl3 is (1, 2)
- vl1 < vl2 is true
- vl1 > vl2 is false
- vl1 == vl2 is false
- vl1 < vl3 is false
- vl1 > vl3 is false
- vl1 == vl3 is true
在这里,我们告诉编译器当它看到<,>,或=作用在我们的新类中该做什么,在别的语言中可以定义成员函数来做同样的事。
Exceptions
异常需要有语言的支持,否则将很难被复制。Windows NT 提供Structured Exception Handing(SEH)的复杂功能,这种由操作系统提供的功能和C++提供的异常是同一种类型。其他语言可以获得SEH带来的好处,而C++的轻便机制使得它能够在所有的操作系统中工作的像SEH一样好。
异常处理正如名字所暗示:有处理异常情况的能力,不会增加正常情况的负担。下面的代码是异常处理。
- DWORD dwStart = ::GetTickCount(); // used for timing in mSec
- const int x = 1000000;
- const int xEnd = -x;
- int y = x;
- int z;
- while ( y > xEnd )
- {
- try
- {
- while ( y > xEnd )
- z = x / y--; // divide protected by exception
- }
- catch (...)
- {
- cout << "Divide by zero" << endl; // trapped out of inner loop
- y--; // continue via outer loop
- }
- }
- DWORD dwStop = ::GetTickCount();
- DWORD dwDiff = dwStop - dwStart;
- CString csMessage;
- csMessage.Format( "mSec = %d", dwDiff );
- cout << (LPCTSTR)csMessage << endl;
输出:
Divide by zero
mSec = 491
内层循环不需要检查是否除0,当发生除0时,把它当成一个异常来处理了。对比没有异常时上面的代码应该写成:
- while ( y > xEnd )
- {
- if ( x != 0 ) // has to execute for every iteration
- {
- z = x / y--;
- }
- else
- {
- cout << "Attempted divide by zero" << endl;
- }
- }
Templates
Function Templates
通过函数模板,可以指定一类函数基于相同的代码,但是不同的类型或是类却有不同的功能。下面是一个模板函数,
返回两个数中的最大值。
- template <class T> T& Max( T& a, T& b )
- {
- if ( a > b ) return a; else return b;
- }
通过这种方式,可以避免MaxFloat
,MaxInt
,MaxShort
,MaxChar等函数的实现。如果调用Max时,使用float,
编译器将会进行编译。由于可以重载运算符,Max函数就不在局限于基本类型。上面的CVeryLong类也能够适用。
Class Templates
- template<class KEY, class ARG_KEY, class DATA, class ARG_DATA>
- class CTree
- {
- private:
- typedef enum
- { balLeft = -1,
- balEven,
- balRight,
- } BALANCE;
- class CNode;
- typedef CNode* PNODE;
- class CNode // container to hold the data and hide the balancing details
- {
- public:
- CNode( ARG_KEY key, ARG_DATA data );
- // additional members not shown
- private:
- KEY m_key;
- DATA m_data;
- BALANCE m_Bal; // -1..1 current balance data for this node
- PNODE m_pLeft;
- PNODE m_pRight;
- };
- CTree(){ m_pRoot = 0; m_nSize = 0; m_bHeightChange = false; }
- virtual ~CTree();
- bool GetFirst( ARG_KEY key, ARG_DATA data );
- bool GetLast( ARG_KEY key, ARG_DATA data );
- bool GetNext( ARG_KEY key, ARG_DATA data );
- bool GetPrev( ARG_KEY key, ARG_DATA data );
- bool Add( ARG_KEY key, ARG_DATA data );
- ARG_DATA operator[]( ARG_KEY key );
- bool Delete( ARG_KEY key );
- // additional members not shown
- private:
- CNode* m_pRoot;
- bool m_bHeightChange;
- int m_nSize;
- };
上面的类通过指定不同类型,将产生新的类,这些类所具有的操作是相同的。
让我们来看下,模板的声明:
template<class KEY, class ARG_KEY, class DATA, class ARG_DATA>
class CTree
在声明中有四个参数,指定键的类型,键的传递方式,数据类型,数据的传递方式
CTree<CString, const char*, CVeryLong,CVeryLong&> treeVeryLong;
CTree<CString, const char*, float,float> treeFloat;
CTree<long, long, CString, constchar*> treeString;
CTree<CVeryLong, CVeryLong,CList<int, int>, <int,int>&> treeList;
第一个例子是一棵以CVeryLong为数据,CString为键的树,键的传递方式是 const char* ,数据的传递
方式是通过引用。
类模板提供了强大的代码重用机制。