无法将NULL转换为指向对象的指针类型

x6h*_*ius 2 c++ pointers c++11

到目前为止,我无法在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:
    ...
};
Run Code Online (Sandbox Code Playgroud)

而(简化)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;
    }

    ...
};
Run Code Online (Sandbox Code Playgroud)

作为测试,我编译了以下代码来创建一个新的SceneObject:

ModuleNS::Scene scene;
ModuleNS::SceneObject* sceneObject =
    scene.createSceneObject<ModuleNS::SceneObject>(NULL);
Run Code Online (Sandbox Code Playgroud)

但是,MSVC编译器给了我以下错误:

无法将参数2从'int'转换为'ModuleNS :: SceneObject*'

这让我很困惑,因为我认为NULL(即0)总是可以转换为指针类型.如果我使用static_cast<ModuleNS::SceneObject*>(NULL),或者nullptr(我想使用它,但为了与我一直使用的旧代码保持一致NULL),编译错误消失了.

具体是什么导致NULL停止可以转换为指针?

AnT*_*AnT 8

该错误与以下示例中的错误具有相同的性质

template <typename T> void foo(T t) {
    void *p = t; // ERROR here
}

int main() {
    foo(NULL);
}
Run Code Online (Sandbox Code Playgroud)

在C++中,只有文字0可以转换为指针类型以产生空指针值.NULL扩展到文字零,这就是为什么你可以用它来直接初始化/赋值/比较指针."直接"是这里的关键词.

但是一旦你通过函数参数提供它,它就不再是文字0,不能再作为空指针常量.

在上面的例子T中推导出一些整数类型.函数内部t只是一个碰巧有值的[run-time]整数0.并且不允许使用任意整数初始化指针.

请注意,在现代C++ NULL中实际上可以定义为nullptr,这将使上面的代码进行编译.但是,对于NULL(作为整体0)的"传统"定义,它不会.