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

时间:2016-10-02 16:20:27

标签: c++ c++11 pointers

到目前为止,我还没能在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停止可转换为指针?

2 个答案:

答案 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值会“在翻译中丢失”。