在ACIS中,很多下行強制(downcast)轉換是安全的,如對一個ENTITY*指針強制使用(BODY*)從來沒有出現過問題。
今天碰到的是api_find_named_attribute這個函數,原型如下。
DECL_GA outcome api_find_named_attribute(
ENTITY* ent,
const char* name,
ATTRIB_GEN_NAME *&ret_att,
AcisOptions *ao = NULL);
我一般用這個的時候,是這樣的操作:
ATTRIB_GEN_NAME *na;//用ATTRIB_GEN_STRING* na 會出錯
api_find_named_attribute(pFace,"名稱",na);
char* cpName = ((ATTRIB_GEN_STRING*)na)->value();//下行強制轉換
其中,ATTRIB_GEN_STRING類的部分定義如下,公有繼承於ATTRIB_GEN_NAME,多了個Value的成員數據和value()的成員函數。
class DECL_GA ATTRIB_GEN_STRING: public ATTRIB_GEN_NAME {
char *Value;
public:
/**
* Returns the string value contained by this attribute.
*/
char const *value() const {return Value;}
上面的操作過後,這樣會得到那個pFace的“名稱”屬性的值cpName。這裏不用dynamic_cast也不會出問題,說明na在函數裏面實際指向的是一個ATTRIB_GEN_STRING對象。
然後想,如果na是ATTRIB_GEN_STRING*類型,是不是就省去了後面的強制轉換或者dynamic_cast操作了?答案是否定的,VS給出了錯誤:無法用 "ATTRIB_GEN_STRING *" 類型的值初始化 "ATTRIB_GEN_NAME *&" 類型的引用(非常量限定)。指針可以上行轉換(upcast),但是指針引用是不可以上行轉換的。
這裏其實是引用的性質問題了,跟上行不上行沒關係了。一方面,引用類似於一個*const的指針,另一方面,引用必須與被引用的對象類型一致(常引用有例外)。考慮這段代碼:
double dou = 2.33;
int &in1 = dou;//報錯,無法用 "double" 類型的值初始化 "int&" 類型的引用(非常量限定)
const int &in2 = dou;//不報錯
是不是跟上面的很相像?括號裏的“非常量限定”非常微妙啊。這說明,如果int類型的in1引用了double類型的dou,那麼int的整數操作就要用在double類型上了,這是不安全的。編譯器可能做了類似下面的操作: double dou= 2.33;
int temp = dou;
int& in1 = temp;
那麼對in1的操作根本應用不到dou上了,但是const引用就不一樣了:反正不能被修改。
所以這個問題應該是ACIS內部做了優化,所以下行轉換不會出問題,看不到它的源碼,只能這樣猜想了。