0

我有这个问题,如果我包含某个标题,我将无法编译。

标题的代码:

//#include "tinyxml2.h"

#pragma once

#include "Camera.h"
#include "Controller.h"
#include "Lights.h"
#include "Mesh.h"

namespace ActorFactory {

    //using namespace tinyxml2;

    template<class T>  
    Actor* createInstance() { 
        return new T; 
    }

    typedef std::map<std::string, Actor*(*)()> class_map;
    class_map test = {
        { "Camera", &createInstance<Camera> }
        //{ "Mesh", &createInstance<Mesh> }
    };
}

来自视觉工作室的完整错误消息:

1>------ Build started: Project: ogl_inf251_ca2, Configuration: Debug Win32     ------
1>  Main.cpp
1>d:\development\inf251\ogl_inf251_ca2\model_obj.h(26): warning C4005:     '_CRT_SECURE_NO_WARNINGS' : macro redefinition
1>          command-line arguments :  see previous definition of     '_CRT_SECURE_NO_WARNINGS'
1>  Generating Code...
1>  Compiling...
1>  Scene.cpp
1>d:\development\inf251\ogl_inf251_ca2\model_obj.h(26): warning C4005:     '_CRT_SECURE_NO_WARNINGS' : macro redefinition
1>          command-line arguments :  see previous definition of     '_CRT_SECURE_NO_WARNINGS'
1>  Generating Code...
1>Scene.obj : error LNK2005: "class std::map<class     std::basic_string<char,struct std::char_traits<char>,class std::allocator<char>     >,class Actor * (__cdecl*)(void),struct std::less<class     std::basic_string<char,struct std::char_traits<char>,class std::allocator<char>     > >,class std::allocator<struct std::pair<class std::basic_string<char,struct     std::char_traits<char>,class std::allocator<char> > const ,class Actor *     (__cdecl*)(void)> > > ActorFactory::test" (?test@ActorFactory@@3V?$map@V?    $basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@P6APAVActor@@XZU?    $less@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@V?    $allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@std@@V?    $allocator@D@2@@std@@P6APAVActor@@XZ@std@@@2@@std@@A) already defined in     Main.obj
1>D:\development\inf251\Debug\ogl_inf251_ca2.exe : fatal error LNK1169: one     or more multiply defined symbols found
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

不幸的是,错误消息真的很长。我不知道如何解决这个问题,甚至不知道出了什么问题。还有更好的方法来按名称实例化类吗?

提前感谢您的帮助:)

4

4 回答 4

4

您的test对象违反了单一定义规则。

防止定义在同一个#pragma once编译单元中出现多次(读取:相同的 *.cpp 文件),但不会出现在不同的编译单元中(读取:不同的 *.cpp 文件)。

解决此问题的一种方法是将对象转换为函数内的静态本地对象,并通过引用使其可访问:

标头.h:

// ...

namespace ActorFactory {

    // ...

    typedef std::map<std::string, Actor*(*)()> class_map;
    class_map& test();
}

测试.cpp:

#include "header.h"

namespace ActorFactory {

    // ...

    class_map& test() {
        static class_map test = {
            { "Camera", &createInstance<Camera> }
            { "Mesh", &createInstance<Mesh> };
        return test;
    }
}

这也是针对所谓的静态初始化命令失败的故障安全保证,并为您提供延迟初始化(这对这个小对象并不重要)。

您可以通过分配对象并从不删除它来使整个事情更加安全(面对破坏顺序问题)new,但该函数仍应返回一个引用

namespace ActorFactory {

    // ...

    class_map& test() {
        static class_map* test = new class_map {
            { "Camera", &createInstance<Camera> }
            { "Mesh", &createInstance<Mesh> };
        return *test;
    }
}

阅读我在上面链接的常见问题解答以获取所有详细信息。

在任何情况下,客户端代码都会简单地通过test()而不是访问对象test

于 2015-03-22T21:20:49.097 回答
3

问题是你声明的方式test

您可以声明它staticconst(在这种情况下暗示static)。但是,对于包含此标头的每个源文件,您将拥有一个单独的副本,这会浪费内存并可能导致其他问题。test

因此,您应该在标头extern class_map test;中声明您的测试,并且只在一个源文件中声明ActorFactory::class_map ActorFactory::test = {...};(如果您将其设为 const,请将 extern 也放入源文件中)。

于 2015-03-22T21:05:36.907 回答
0

在我看来,您在标头中实例化了“测试”变量,该变量包含在 Main.Cpp 和 Scene.Cpp 中。不 ?

如果您的标头包含在两个 .cpp 文件中,则会导致符号重复。#pragma once 只防止在编译同一个源文件时多次包含头文件,但在编译另一个源代码时仍然可以包含第二次。

于 2015-03-22T21:05:38.740 回答
-1

看起来它在抱怨重新定义test. 改名试试?

于 2015-03-22T21:03:37.893 回答