未定义的对xx :: xx()的引用

时间:2017-09-27 14:25:57

标签: c++11 linker

当我告诉你我在线搜索但未找到答案时,请相信我。

我有5个文件:

的main.cpp

Game.cpp

Game.hpp

Window.cpp

Window.hpp

内容如下:

#include "Window.hpp"
#include "Game.hpp"

int main()
{
    // Program entry point
    Game game;
    while (!game.GetWindow()->IsDone()){
        // game loop here
        game.HandleInput();
        game.Update();
        game.Render();
    }
    return 0;
}

这是Game.cpp

#include "Window.hpp"

class Game {
    public:
        Game(): m_window("Chapter 2", sf::Vector2u(800,600)) {

            m_mushroomTexture.loadFromFile("images.png");
            m_mushroom.setTexture(m_mushroomTexture);
        }
        ~Game(){}

        void HandleInput() {

        }
        void Update() {
            m_window.Update();
            MoveMushroom();
        }
        void Render() {
            m_window.BeginDraw();
            m_window.Draw(m_mushroom);
            m_window.EndDraw();
        }
        // Getting a point to the window
        Window* GetWindow(){

        }

    private:
        void MoveMushroom(){
            sf::Vector2u l_windSize = m_window.GetWindowSize();
            sf::Vector2u l_textSize = m_mushroomTexture.getSize();

            if ((m_mushroom.getPosition().x > l_windSize.x - l_textSize.x and m_increment.x > 0) or \
                (m_mushroom.getPosition().x < 0 and m_increment.x < 0)) {
                m_increment.x = -m_increment.x;
            }
            if ((m_mushroom.getPosition().y > l_windSize.y - l_textSize.y and m_increment.y > 0) or \
                (m_mushroom.getPosition().y < 0 and m_increment.y < 0)) {
                m_increment.y = -m_increment.y;
            }
            m_mushroom.setPosition( m_mushroom.getPosition().x + m_increment.x, m_mushroom.getPosition().y + m_increment.y);
        }
        Window m_window;
        sf::Texture m_mushroomTexture;
        sf::Sprite m_mushroom;
        sf::Vector2i m_increment;
};

Game.hpp

#pragma once

#include "Window.hpp"
#include <SFML/Graphics.hpp>

class Game {
public:
    Game();
    ~Game();

    void HandleInput();
    void Update();
    void Render();
    // Getting a point to the window
    Window* GetWindow();

private:
    void MoveMushroom();
    Window m_window;
    sf::Texture m_mushroomTexture;
    sf::Sprite m_mushroom;
    sf::Vector2i m_increment;
};

Window.cpp

#include <SFML/Graphics.hpp>
#include <string>


class Window {
public:
    // constructor
    Window() {Setup("Window", sf::Vector2u(640,480));}
    // we have 2 constructors because there 2 ways to instantiate a class

    Window(const std::string& l_title, const sf::Vector2u& l_size) {

        Setup(l_title, l_size);
    }
    ~Window() { Destroy(); }

    void BeginDraw(){
        m_window.clear(sf::Color::Black);
    }
    void EndDraw(){
        m_window.display();
    }

    void Update(){

        sf::Event event;
        while (m_window.pollEvent(event)) {
            if (event.type == event.Closed) {
                m_isDone = true;
            } else if (event.type == sf::Event::KeyPressed and event.key.code == sf::Keyboard::F5){
                ToggleFullscreen();
            }
        }

    }

    bool IsDone(){
        return m_isDone;
    }
    bool IsFullscreen(){
        return m_isFullscreen;
    }

    sf::Vector2u GetWindowSize() {
        return m_windowSize;
    }

    void ToggleFullscreen(){
        m_isFullscreen = !m_isFullscreen;
        Destroy();
        Create();
    }

    void Draw(sf::Drawable& l_drawable){
        m_window.draw(l_drawable);
    }

private:
    void Setup(const std::string& l_title, const sf::Vector2u& l_size) {
        m_windowTitle = l_title;
        m_windowSize = l_size;
        m_isFullscreen = false;
        m_isDone = false;
        Create();
    }

    void Destroy(){
        m_window.close();
    }

    void Create() {
        // the same as 
        // if (m_isFullscreen) {
        //      auto_style = sf::Style::Fullscreen;
        // } else {
        //      auto_style = sf::Style::Default;
        // }
        auto style = (m_isFullscreen ? sf::Style::Fullscreen : sf::Style::Default);
        m_window.create({m_windowSize.x, m_windowSize.y, 32}, m_windowTitle, style);
    }

    sf::RenderWindow m_window;
    sf::Vector2u m_windowSize;
    std::string m_windowTitle;
    bool m_isDone;
    bool m_isFullscreen;

};

Window.hpp

#pragma once

#include <SFML/Graphics.hpp>
#include <string>

class Window {
public:
    // constructor
    Window();
    // we have 2 constructors because there 2 ways to instantiate a class
    Window(const std::string& l_title, const sf::Vector2u& l_size);
    ~Window();

    void BeginDraw();
    void EndDraw();

    void Update();

    bool IsDone();
    bool IsFullscreen();
    sf::Vector2u GetWindowSize();

    void ToggleFullscreen();

    void Draw(sf::Drawable& l_drawable);
private:
    void Setup(const std::string& l_title, const sf::Vector2u& l_size);
    void Destroy();
    void Create();

    sf::RenderWindow m_window;
    sf::Vector2u m_windowSize;
    std::string m_windowTitle;
    bool m_isDone;
    bool m_isFullscreen;

};

问题是,当我尝试构建我的项目时,我收到链接器错误。

/tmp/ccxbe5nA.o: In function `main':
main.cpp:(.text+0x26): undefined reference to `Game::Game()'
main.cpp:(.text+0x35): undefined reference to `Game::GetWindow()'
main.cpp:(.text+0x3d): undefined reference to `Window::IsDone()'
main.cpp:(.text+0x53): undefined reference to `Game::HandleInput()'
main.cpp:(.text+0x62): undefined reference to `Game::Update()'
main.cpp:(.text+0x71): undefined reference to `Game::Render()'
main.cpp:(.text+0x87): undefined reference to `Game::~Game()'
main.cpp:(.text+0xac): undefined reference to `Game::~Game()'
collect2: error: ld returned 1 exit status

我首先使用以下命令编译:

g++ -std=c++11  -c main.cpp Window.cpp Game.cpp

编译阶段没有错误。当我尝试链接它时,我从上面收到错误消息。使用的命令是:

g++ main.o Game.o Window.o -o sfml-app -lsfml-graphics -lsfml-window -lsfml-system

2 个答案:

答案 0 :(得分:2)

通过在不同位置以不同方式定义同一个类,您的程序违反了一个定义规则:

  

[basic.def.odr] / 5 在程序中可以有多个类类型的定义...如果每个定义出现在不同的翻译单元中,并且提供了定义满足以下要求。鉴于在多个翻译单元中定义了名为D的实体,那么

     

- D的每个定义都包含相同的令牌序列;和...

强调我的。

Game.cpp删除类定义,只保留成员函数定义,如下所示:

Game::Game(): m_window("Chapter 2", sf::Vector2u(800,600)) {...}
void Game::Update() {...}
// and so on for other members

同样适用于Window

答案 1 :(得分:1)

您将每个类定义两次,这是不正确的。

.cpp文件中,它需要为已声明但未在标题中定义的函数提供定义。

例如,Windows.cpp应包含Windows.hpp并包含:

bool Windows::IsDone() {
    return m_isDone;
}