0

我有一个非常简单的代码问题我正在关注 chrono::engine http://www.chronoengine.info/mediawiki/index.php/Demo_fourbar的教程 我在 C++ 编程方面没有太多经验(我有一些 Java 经验),因此我尝试在不同的文件(MyEventReceiver.h 和 MyEventReceiver.cpp)中定义 MyEventReceiver(教程中的一个类),以了解 C++ 代码的经典结构

这是代码的版本

MyEventReceiver.h

#ifndef RECEIVER_H
#define RECEIVER_H

#include "physics/CHapidll.h"
#include "physics/CHsystem.h"
#include "irrlicht_interface/CHbodySceneNode.h"
#include "irrlicht_interface/CHbodySceneNodeTools.h"
#include "irrlicht_interface/CHdisplayTools.h"
#include "irrlicht_interface/CHirrWizard.h"
#include "core/CHrealtimeStep.h"

#include <irrlicht.h>


// Use the namespace of Chrono
using namespace chrono;

// Use the main namespaces of Irrlicht
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

class MyEventReceiver : public IEventReceiver
{
public:
    MyEventReceiver(ChSystem* asystem, IrrlichtDevice* adevice,     ChSharedPtr<ChLinkEngine> aengine);
    bool OnEvent(const SEvent& event);
    void setText_enginespeed(IGUIStaticText* _text_enginespeed);
    IGUIStaticText* getText_enginespeed();
private:
    IGUIStaticText* text_enginespeed;
    ChSystem*       msystem;
    IrrlichtDevice* mdevice;
    ChSharedPtr<ChLinkEngine> mengine;
};

#endif

在 MyEventReceiver.cpp 中实现如下

#include "MyEventReceiver.h"


// Constructor
MyEventReceiver::MyEventReceiver(ChSystem *asystem, IrrlichtDevice *adevice, ChSharedPtr<ChLinkEngine> aengine)
{
    // store pointer to physical system & other stuff
    // so we can tweak them by user keyboard
    msystem = asystem;
    mdevice = adevice;
    mengine = aengine;
}



bool MyEventReceiver::OnEvent(const SEvent& event)
{
    // check if user moved the sliders with mouse..
        if (event.EventType == EET_GUI_EVENT)
        {
            s32 id = event.GUIEvent.Caller->getID();
            IGUIEnvironment* env = mdevice->getGUIEnvironment();

            switch(event.GUIEvent.EventType)
            {
            case EGET_SCROLL_BAR_CHANGED:
                    if (id == 101) // id of 'engine speed' gui
                    {
                        s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
                        double newspeed = 10*(double)pos/100.0;

                        // set the speed into engine object
                        ChFunction_Const *spe_funct = dynamic_cast <ChFunction_Const*> (mengine->Get_spe_funct());
                        spe_funct->Set_yconst(newspeed);


                        // show speed as formatted text in interface screen
                        char message[50]; sprintf(message,"Engine speed: %g [rad/s]",newspeed);
                        text_enginespeed->setText(core::stringw(message).c_str());

                    }
            break;
            }

        }

        return false;
}


void MyEventReceiver::setText_enginespeed(IGUIStaticText* _text_enginespeed)
{
    text_enginespeed = _text_enginespeed;
}


IGUIStaticText* MyEventReceiver::getText_enginespeed()
{
    return text_enginespeed;
}

和 Main_2.cpp 中的主文件(我清空了它,无论有没有代码,它都会给我同样的错误 - 这基本上只是设置 3D 引擎 Irrlicht 和 chrono::engine 的碰撞模型中的一些力学特性)

#include "MyEventReceiver.h"

int main()
{
    return 0;
}

基本上,代码定义了一个事件接收器,以便用户在运行程序后可以通过 GUI 操作与由 chrono::engine 和 Irrlicht 引擎构建的 3D 环境交互我在 MyEventReceiver.h 文件中定义了所有必需的库和所需的库命名空间

问题是它无法编译(请注意,我已经测试了引擎 - 使用相同的#include 并在一个文件中使用命名空间并且它在不同的项目中工作 - ),我认为问题来自结构的头文件

我得到了那些错误行

1>MyEventReceiver.obj : error LNK2005: "public: virtual bool __thiscall irr::scene::RTSCamera::OnEvent(struct irr::SEvent const &)" (?OnEvent@RTSCamera@scene@irr@@UAE_NABUSEvent@3@@Z) already defined in Main_2.obj
1>MyEventReceiver.obj : error LNK2005: "public: virtual void __thiscall irr::scene::RTSCamera::OnRegisterSceneNode(void)" (?OnRegisterSceneNode@RTSCamera@scene@irr@@UAEXXZ) already defined in Main_2.obj

等等......(它继续这样)和最后的错误

1>C:\Users\****\Documents\Visual Studio 2010\Projects\TutorialChronoEngine\Debug\TutorialChronoEngine_2.exe : fatal error LNK1169: one or more multiply defined symbols found

我正在使用 Visual Studio 2010 C++。我定义了一个全局解决方案,并在这个解决方案中定义了几个项目(我上面编写的程序是其中一个项目)我确信它一定很容易解决,但无法真正找到解决方案。如果您需要更多详细信息,请告诉我

非常感谢最好的问候文森特

编辑:如果我将所有代码放在一个文件中,如下所示

#include "physics/CHapidll.h"
#include "physics/CHsystem.h"
#include "irrlicht_interface/CHbodySceneNode.h"
#include "irrlicht_interface/CHbodySceneNodeTools.h"
#include "irrlicht_interface/CHdisplayTools.h"
#include "irrlicht_interface/CHirrWizard.h"

#include <irrlicht.h>



// Use the namespace of Chrono

using namespace chrono;

// Use the main namespaces of Irrlicht
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

// Get rid of the command windows that pops up when compiling and running
#ifdef _IRR_WINDOWS_
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif

IGUIStaticText* text_enginespeed = 0;

class MyEventReceiver : public IEventReceiver
{
public:

    MyEventReceiver(ChSystem* asystem,
                    IrrlichtDevice *adevice,
                    ChSharedPtr<ChLinkEngine> aengine)
    {
        // store pointer to physical system & other stuff
        // so we can tweak them by user keyboard
        msystem = asystem;
        mdevice = adevice;
        mengine = aengine;
    }

    bool OnEvent(const SEvent& event)
    {

        // check if user moved the sliders with mouse..
        if (event.EventType == EET_GUI_EVENT)
        {
            s32 id = event.GUIEvent.Caller->getID();
            IGUIEnvironment* env = mdevice->getGUIEnvironment();

            switch(event.GUIEvent.EventType)
            {
            case EGET_SCROLL_BAR_CHANGED:
                    if (id == 101) // id of 'engine speed' gui
                    {
                        s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
                        double newspeed = 10*(double)pos/100.0;

                        // set the speed into engine object
                        ChFunction_Const *spe_funct = dynamic_cast <ChFunction_Const*> (mengine->Get_spe_funct());
                        spe_funct->Set_yconst(newspeed);

                        // show speed as formatted text in interface screen
                        char message[50]; sprintf(message,"Engine speed: %g [rad/s]",newspeed);
                        text_enginespeed->setText(core::stringw(message).c_str());
                    }
            break;
            }

        }

        return false;
    }

private:
    ChSystem*       msystem;
    IrrlichtDevice* mdevice;
    ChSharedPtr<ChLinkEngine> mengine;
};



int main(int argc, char* argv[])
{

    return 0;
}

这样,我避免了从 Irrlicht 3D 引擎定义多次未定义为内联的函数。不幸的是,如果项目变得很大(必须在一个唯一的 .cpp 文件中定义所有依赖于 3D 引擎的类),这种编码方式会变得非常麻烦,是否有一种设计模式可以遵循,以便可以避免多个定义的对象,每个类都定义在一个单独的文件中?

非常感谢

最好的

文森特

4

1 回答 1

2

链接器抱怨您的两个函数被多次定义。正如您可能从错误中找出的那样,这些功能是:

irr::scene::RTSCamera::OnEvent(struct irr::SEvent const &)
irr::scene::RTSCamera::OnRegisterSceneNode(void)

这里最有可能发生的是这两个函数是在头文件中定义的,但是:

  • 它们的定义没有直接出现在类定义中(因此它们没有被隐式声明为内联);
  • 它们在头文件中的类外定义未明确标记为内联。

因此,如果在不同的翻译单元(即不同的.cpp文件)中多次包含标头,则相同函数的多个定义最终将出现在这些翻译单元的目标代码中。

合并它们时,链接器会抱怨您违反了 ODR(一个定义规则)。

于 2013-02-09T13:31:51.940 回答