这里随手记录了一个关于常量指针参数的编译错误,
顺道引出指针常量和常量指针这个经常容易混淆的话题。
起因
手动编译fear::vision模块的时候出现的编译错误
错误信息
error C2664: “fear::backend::iVision::NextEntity”: 不能将参数1 从“fear::Entity *”转换为 “const fear::Entity *& ”
转换丢失限定符
错误类别
错误的类型转换
代码如下
void VisionSymbolic::GetVisibleEntities(vector < Entity * >& visible)
... {
Entity* e = NULL;
GetBackend().Reset();
while (GetBackend().NextEntity(e))
...{
visible.push_back(e);
}
} // GetVisibleEntities()
错误的原因:
const指针引用编译不能通过!
NextEntity的函数头如下:
这是1个常量指针引用, 而不是指针常量引用!
试验
首先使用VC8做了一下测试, 编译无法通过
1. 常量指针的引用,编译错误
{
return;
}
int _tmain( int argc, _TCHAR * argv[])
{
int* testInt = 0;
testConstPtrRef(testInt); // 错误!输入不是要求的常量指针引用
return 0;
}
在GCC下的同样也产生错误, 错误信息如下
from expression of type 'int*'
main.cpp:8: error: in passing argument 1 of `void testConstPtrRef(const int*&) '
这种明显的错误在VC6和VC7是可以编译过的? 我没试过...谁试验下?
2. 使用了1个typdef, 被指定为指针IntPtr的常量引用,编译通过
void testConstPtrRef( const IntPtr & intPtrRef)
{
return;
}
int _tmain( int argc, _TCHAR * argv[])
{
IntPtr testInt = 0; // Int* 在这里同样可以
testConstPtrRef(testInt); // 通过!指针的常量引用
return 0;
}
3. 把const 放在后面,指针类型的常量引用,编译通过
{
return;
}
int _tmain( int argc, _TCHAR * argv[])
{
int* testInt = 0;
testConstPtrRef(testInt);
return 0;
}
2和3在GCC下同样通过!
修改GetVisibleEntities函数
下面还是回到编译问题上来, 一开始我直接定义vector< const Entity* > 返回。
void VisionSymbolic::GetVisibleEntities( EntityVec & visible)
{
const Entity* e = NULL; <- 这里直接传const指针给NextEntity
GetBackend().Reset();
while (GetBackend().NextEntity(e))
{
visible.push_back(e);
}
} // GetVisibleEntities()
但是上面的方法在FEAR::VisionSymbolic里是无法这么写..
原因是
GetVisibleEntities是iSymbolic接口的实现。所以我们还是只能在内部修改
但是我们又不能修改接口的实现为const Entity*, 那该怎么办呢?
暂时只能用这种脑残做法了--------------使用const_cast 囧
{
const Entity* ce = NULL; //<- 此处依然是const, 为了获得实体
GetBackend().Reset();
while (GetBackend().NextEntity(ce))
{
visible.push_back( const_cast<Entity*>(ce) ); // const_cast!
}
} // GetVisibleEntities()
结论
常量指针使用错误的可以使用如下方法解决:
1 把const写在参数类型后面
似乎boost和一些库里更倾向于把const放在后面, 大概就是为了避免出现上面的问题吧。
不过总觉得把const放后面感觉很奇怪, 大概是看前面看多了吧...
2 使用typedef声明别名
如上面typedef int*为IntPtr;
你可以使用类简单封装指针。
也可以使用一个这样的宏定义
typedef Type * CLASS##Ptr;
3 不改变函数体, 直接传常量指针参数
这个就是我上面用的方法。这样就不用修改内部实现。
4 使用const_cast
const_cast似乎一向都不受推荐使用来的?
以上....= =||| 记录美....