到目前为止,我还没能在Google上找到关于以下内容的解释,这让我感到困惑。
我有Scene
存储SceneObjects
的层次结构。 Scene
充当模板SceneObject
工厂,因此可以在创建或删除SceneObject
子类实例时完成簿记。这两个类都在它们自己的动态链接模块中,并且在模块命名空间内(不确定这是否重要)。
(简化)SceneObject
类看起来像这样:
// SceneObject is a base class, but is not pure.
class SceneObject
{
// The parent Scene needs to be able to access protected functions.
friend class Scene;
protected:
// This is protected to enforce the factory design pattern.
// We don't want SceneObjects created without being tied to a Scene.
SceneObject(Scene* parentScene, SceneObject* parentObject);
public:
...
};
(简化的)Scene
类看起来像这样:
class Scene
{
public:
// General bookkeeping - a fully constructed subclass is required
// here as the subclass constructor sets certain member variables.
void processSceneObjectCreated(SceneObject* object);
// This function means we can do:
// SceneObjectSub* obj = scene.createSceneObject<SceneObjectSub>(...)
// and pass whatever parameters are required for that particular
// subclass' constructor, while ensuring the Scene can keep a record
// of the created object.
//
// We can't call processSceneObjectCreated() in the SceneObject base
// class' constructor, as the required subclass constructor will not
// have been run yet.
template<typename T, typename... Args>
T* createSceneObject(Args... args)
{
T* obj = new T(this, std::move(args)...);
processSceneObjectCreated(obj);
return obj;
}
...
};
作为测试,我编译了以下代码以创建新的SceneObject
:
ModuleNS::Scene scene;
ModuleNS::SceneObject* sceneObject =
scene.createSceneObject<ModuleNS::SceneObject>(NULL);
但是,MSVC编译器给了我以下错误:
无法从&#39; int&#39;转换参数2到&#39; ModuleNS :: SceneObject *&#39;
这让我很困惑,因为我认为NULL
(即0)总是可以转换为指针类型。相反,我使用static_cast<ModuleNS::SceneObject*>(NULL)
或nullptr
(我想使用它,但为了与旧代码保持一致,我一直在使用NULL
) ,编译错误就消失了。
什么特别导致NULL停止可转换为指针?
答案 0 :(得分:8)
错误与以下示例
中的错误具有相同的性质template <typename T> void foo(T t) {
void *p = t; // ERROR here
}
int main() {
foo(NULL);
}
在C ++中,只有文字0
可以转换为指针类型以产生空指针值。 NULL
扩展为字面零,这就是为什么你可以用它来直接初始化/分配/比较指针 。 “直接”是这里的关键词。
但是一旦你通过函数参数提供它,它就不再是文字0
而且不能再作为空指针常量。
在上面的示例中,T
被推断为某种整数类型。函数t
内部只是一个[run-time]整数,恰好有值0
。并且不允许使用任意整数初始化指针。
请注意,在现代C ++中,NULL
实际上可以定义为nullptr
,这将使上述代码进行编译。但是,对于NULL
(作为整数0
)的“传统”定义,它不会。
答案 1 :(得分:1)
将NULL
替换为C ++的nullptr
。
当NULL通过std::move
清洗时,NULL展开的0值会“在翻译中丢失”。