Conversion Operators in OpenCascade
eryar@163.com
Abstract. C++ lets us redefine the meaning of the operators when applied to objects. It also lets us define conversion operations for class types. Class-type conversions are used like the built-in conversions to implicitly convert an object of one type to another type when needed. A conversion operator provides a way for you to define how an object can be converted automatically to a different type. The paper gives some conversion operators examples in OpenCascade.
Key words. OpenCascade, Conversion Operators, Operator overloading
1. Introduction
C++允許我們重新定義操作符用于類類型對象時的含義。如果需要,可以像內置轉換那樣使用類類型轉換,將一個類型對象隱式轉換到另一類型。如在OpenCascade中經常看到如下類似的代碼:
TopoDS_Shape theSphere = BRepPrimAPI_MakeSphere(1.0);
其中,BRepPrimAPI_MakeSphere也是一個類,直接賦值給了另一個類TopoDS_Shape的對象theSphere。第一次這么來用的時候有些困惑,不知道你有沒有這樣的疑問,不管你有沒有,反正我是有的(Just kidding)。后來才知道,這就是一種重載方式,重載了類型轉換操作符(Conversion Operator)。
使用類型轉換操作符在將一種類型轉換到另一種類型時,感覺自然。當類較多且經常需要進行類型之間的轉換時,定義類型轉換操作符還是很方便的。本文結合OpenCascade程序來體驗使用類型轉換操作符帶來的便利。
2. Conversion Operators
轉換操作符(Conversion Operators)提供了從一種對象類型自動轉換到另一種類型的方式。一個經典例子就是自定義字符串類,但是可以將這個自定義的字符串類當作函數參數傳給const char*類型的函數,如標準C中的一些函數:strcmp(), strlen()。示例程序如下所示:
class MyString
{
public:
MyString(const char* string);
// convert MyString to a C-style string.
operator const char*() { return mBuffer; }
private:
char* mBuffer;
int mLength;
};
// MyString objects get automatically converted to const char*
MyString mystr("Haggis");
int same = strcmp(mystr, "Edible");
int len = strlen(mystr);
轉換操作符是一種特殊的類成員函數。它定義將類類型值轉換為其他類型值的轉換。轉換操作符在類定義體內聲明,在關鍵字operator之后跟著轉換的目標類型。轉換操作符的通用形式為:
operator type();
轉換函數必須是成員函數,不能指定返回類型,且形參表必須為空。因為轉換的目標類型已經出現在轉換操作符中了,所以就不需要重復定義返回值類型了。
3. Conversion Operators in OpenCascade
OpenCascade中很多地方用到了轉換操作符,如將生成的基本實體轉換成其他拓樸類型時就用到了轉換操作符,程序代碼如下所示:
/*
* Copyright (c) 2014 eryar All Rights Reserved.
*
* File : Main.cpp
* Author : eryar@163.com
* Date : 2014-04-12 18:02
* Version : V1.0
*
* Description : Learn Conversion Operators in OpenCascade.
*
* Key words : OpenCascade, Conversion Operators
*
*/
#define WNT
#include <BRepPrimAPI_MakeSphere.hxx>
#pragma comment(lib, "TKernel.lib")
#pragma comment(lib, "TKMath.lib")
#pragma comment(lib, "TKBRep.lib")
#pragma comment(lib, "TKPrim.lib")
#pragma comment(lib, "TKTopAlgo.lib")
void TestConversionOperators(void)
{
TopoDS_Shape theSphereShape = BRepPrimAPI_MakeSphere(1.0);
TopoDS_Solid theSphereSolid = BRepPrimAPI_MakeSphere(1.0);
TopoDS_Shell theSphereShell = BRepPrimAPI_MakeSphere(1.0);
TopoDS_Face theSphereFace = BRepPrimAPI_MakeSphere(1.0);
// error C2440: 'initializing' : cannot convert
// from 'BRepPrimAPI_MakeSphere' to 'TopoDS_Wire'
//TopoDS_Wire theSphereWire = BRepPrimAPI_MakeSphere(1.0);
}
int main(int argc, char* argv[])
{
TestConversionOperators();
return 0;
}
如上代碼所示,可以將類BRepPrimAPI_MakeSphere自動轉換成TopoDS_Shape, TopoDS_Solid, TopoDS_Shell, TopoDS_Face,但是不能自動轉換成TopoDS_Wire。這是因為在其父類BRepPrimAPI_MakeOneAxis中定義這些轉換操作符,代碼如下所示:
//! The abstract class MakeOneAxis is the root class of <br>
//! algorithms used to construct rotational primitives. <br>
class BRepPrimAPI_MakeOneAxis : public BRepBuilderAPI_MakeShape {
public:
DEFINE_STANDARD_ALLOC
//! The inherited commands should provide the algorithm. <br>
//! Returned as a pointer. <br>
Standard_EXPORT virtual Standard_Address OneAxis() = 0;
//! Stores the solid in myShape. <br>
Standard_EXPORT virtual void Build() ;
//! Returns the lateral face of the rotational primitive. <br>
//! <br>
Standard_EXPORT const TopoDS_Face& Face() ;
Standard_EXPORT operator TopoDS_Face();
//! Returns the constructed rotational primitive as a shell. <br>
Standard_EXPORT const TopoDS_Shell& Shell() ;
Standard_EXPORT operator TopoDS_Shell();
//! Returns the constructed rotational primitive as a solid. <br>
Standard_EXPORT const TopoDS_Solid& Solid() ;
Standard_EXPORT operator TopoDS_Solid();
protected:
private:
};
由上述代碼可知,當將BRepPrimAPI_MakeSphere賦值給TopoDS_Shape時,會調用operator TopoDS_Shape()轉換操作符的轉換函數;當賦值給TopoDS_Shell時,會調用operator TopoDS_Shell()轉換函數,等等。未定義的轉換類型是不允許自動轉換的,如TopoDS_Wire。
使用這些轉換操作符使不同類型之間的類型轉換很自然直觀,看上去就像調用了一個函數。
類型之間的轉換當然還有其他方法,如給轉換的目標類型增加一個構造函數來實現。但是使用構造函數來轉換不能轉換成基本類型,如int, double等;還有個不足之處就是要修改轉換目標類的聲明文件來增加一個構造函數。沒有轉換操作符來得自然,方便。
4. Conclusion
當需要在不同類型之間進行類型轉換時,可以使用轉換操作符(Conversion Operators)。使用轉換操作符的方式別其他方法要簡單直觀。
由于OpenCascade中類型比較多,且經常需要要不同類型之間進行轉換操作,所以將一些常用的轉換定義成轉換操作符還是很方便的。
5. References
1. Bjarne Stroustrup. The C++ programming language. Higher Education Press. 2009
2. Stanley B. Lippman, Josee Lajoie, Barbara E. Moo. C++ Primer. Addison Wesley. 2005
3. Martin Reddy. API Design for C++. Morgan Kaufmann. 2011