作者:朱金燦
最近對函數返回值的設計有了一些新的思考。前一陣子頭檢查我寫的代碼。我的代碼大致如下(憑記憶):
#include <stdio.h>
#include <float.h>
#include <string>
using std::string;
#include <vector>
using std::vector;
/*! @struct stExtent
* @brief
*
* 地理范圍結構體,實現對地理范圍的各種操作,如合並
* @author zjc
* @version 0.1
* @date 2010.08.10
*/
struct stExtent
{
stExtent()
{
m_fMinX = -FLT_MAX;
m_fMaxX = FLT_MAX;
m_fMinY = -FLT_MAX;
m_fMaxY = FLT_MAX;
}
/*!
* @brief 合並兩個地理范圍
*
* @param [in]Other 另一個地理范圍
* @return 新的地理范圍
*/
stExtent operator + (stExtent &Other)
{
m_fMinX = std::min(m_fMinX,Other.m_fMinX);
m_fMaxX = std::max(m_fMaxX,Other.m_fMaxX);
m_fMinY = std::min(m_fMinY,Other.m_fMinY);
m_fMaxY = std::max(m_fMaxY,Other.m_fMaxY);
return *this;
}
void operator = (stExtent &Other)
{
m_fMinX = Other.m_fMinX;
m_fMaxX = m_fMaxX,Other.m_fMaxX;
m_fMinY = m_fMinY,Other.m_fMinY;
m_fMaxY = m_fMaxY,Other.m_fMaxY;
}
/**
* @brief X方向的最小值
*/
float m_fMinX;
/**
* @brief X方向的最大值
*/
float m_fMaxX;
/**
* @brief Y方向的最小值
*/
float m_fMinY;
/**
* @brief Y方向的最大值
*/
float m_fMaxY;
};
/*! @class CDrawObj
* @brief
*
* 顯示對象基類
* @author zjc
* @version 0.1
* @date 2010.08.10
*/
class CDrawObj
{
public:
CDrawObj()
{
m_Extent.m_fMinX = 0.0f;
m_Extent.m_fMinY = 0.0f;
m_Extent.m_fMaxX = 100.0f;
m_Extent.m_fMaxY = 100.0f;
}
/*!
* @brief 獲取顯示對象的地理范圍
* @return 顯示對象的地理范圍
*/
stExtent& GetExtent()
{
return m_Extent;
}
protected:
private:
/**
* @brief 顯示屬性數組
*/
std::vector<stProperty> m_vecPropertys;
/**
* @brief 地理范圍
*/
stExtent m_Extent;
};
/*! @class CDrawObj
* @brief
*
* 顯示對象基類
* @author zjc
* @version 0.1
* @date 2010.08.10
*/
class CDrawObj
{
public:
CDrawObj()
{
m_Extent.m_fMinX = 0.0f;
m_Extent.m_fMinY = 0.0f;
m_Extent.m_fMaxX = 100.0f;
m_Extent.m_fMaxY = 100.0f;
}
/*!
* @brief 獲取顯示對象的地理范圍
* @param Extent 求取的地理范圍
* @return 顯示對象的地理范圍
*/
void GetExtent(stExtent& Extent)
{
Extent = m_Extent;
}
protected:
private:
/**
* @brief 顯示屬性數組
*/
std::vector<stProperty> m_vecPropertys;
/**
* @brief 地理范圍
*/
stExtent m_Extent;
};
頭建議我將CDrawObj類的GetExtent函數改為如下:
stExtent& GetExtent()
{
return m_Extent;
}
我說:"這樣是為了方便實現鏈式表達式嗎?"我的意思是:照頭的改法,外部可以這樣調用:stExtent TmpExtent = Obj1. GetExtent() + Obj1. GetExtent();頭說:"不完全是,你想照你的做法,用戶必須先定義一個stExtent變量,再把它傳進函數。"我說:"這源於我的習慣認識,我認為renturn 返回的值用於判斷操作是否成功"。不過這次頭確實說的有道理,因為這個操作的返回值是void,那麼直接返回操作結果值更為合理。
今天見到這樣一個類的函數這樣寫:
struct stProperty
{
stProperty()
{
m_strName = _T("");
}
/**
* @brief 顯示屬性名
*/
std::string m_strName;
};
/*!
* @brief 給出一個屬性名字,查找這個屬性
*
* @param [in]strProName 給定的屬性名字
* @return 屬性
*/
stProperty Invalid_Property;
stProperty SearchProperty(const std::string strProName) const
{
//m_vecPropertys為一個類的屬性數組先循環屬性數組,找出符合條件的數組,
// 若不存在,拋出異常並返回錯誤屬性
try
{
for (size_t i =0;i<m_vecPropertys.size();i++)
{
if (strProName==m_vecPropertys[i].m_strName)
{
return m_vecPropertys[i];
}
}
}
catch (...)
{
}
throw _T("cannot find Property");
return Invalid_Property;
}
我覺得這樣設計並不合理,如果讓我設計的話,我會這樣設計這個函數:
BOOL SearchProperty(const std::string strProName,stProperty &prop),
用BOOL變量返回值來判斷是否存在這樣的屬性,用變量prop來保存查找結果。
為此我總結了一下設計函數的一些心得:首先判斷是否需要操作是否成功、值是否存在,若不需要,考慮直接返回操作結果(即由renturn語句返回而不是通過輸出參數返回),畢竟這樣外部調用比較方便,若需要,則應設計為通過輸出參數返回操作結果值。