在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内部做了优化,所以下行转换不会出问题,看不到它的源码,只能这样猜想了。