Mac CMake C++;体系结构x86_64的SDL2重复符号 我在YouTube上介绍了一个关于C++和SDL2的教程,这是在2017中完成的,我不能因为这个错误而进步。我刚开始在Mac上工作,并假设错误是由于CMake或使用VS代码造成的,所以我安装了Qt creator,但仍然会遇到相同的错误。我已经研究过这个错误,但我不明白问题是什么,希望有人能帮助我理解。我的假设是它与Game.cpp中带有新GameObject和新地图的线条有关

Mac CMake C++;体系结构x86_64的SDL2重复符号 我在YouTube上介绍了一个关于C++和SDL2的教程,这是在2017中完成的,我不能因为这个错误而进步。我刚开始在Mac上工作,并假设错误是由于CMake或使用VS代码造成的,所以我安装了Qt creator,但仍然会遇到相同的错误。我已经研究过这个错误,但我不明白问题是什么,希望有人能帮助我理解。我的假设是它与Game.cpp中带有新GameObject和新地图的线条有关,c++,macos,cmake,sdl-2,C++,Macos,Cmake,Sdl 2,谢谢你的帮助 错误: 18:19:19: Running steps for project cpp... 18:19:19: Starting: "/Users/m/Qt/Tools/CMake/CMake.app/Contents/bin/cmake" --build . --target all [1/6 2.1/sec] Building CXX object CMakeFiles/cpp.dir/GameObject.cpp.o [2/6 4.2/sec] Buil

谢谢你的帮助

错误:

18:19:19: Running steps for project cpp...
18:19:19: Starting: "/Users/m/Qt/Tools/CMake/CMake.app/Contents/bin/cmake" --build . --target all
[1/6 2.1/sec] Building CXX object CMakeFiles/cpp.dir/GameObject.cpp.o
[2/6 4.2/sec] Building CXX object CMakeFiles/cpp.dir/TextureManager.cpp.o
[3/6 6.2/sec] Building CXX object CMakeFiles/cpp.dir/main.cpp.o
[4/6 8.3/sec] Building CXX object CMakeFiles/cpp.dir/Map.cpp.o
[5/6 10.2/sec] Building CXX object CMakeFiles/cpp.dir/Game.cpp.o
[6/6 8.8/sec] Linking CXX executable cpp
FAILED: cpp 
: && /usr/bin/clang++  -g -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names  CMakeFiles/cpp.dir/main.cpp.o CMakeFiles/cpp.dir/Game.cpp.o CMakeFiles/cpp.dir/GameObject.cpp.o CMakeFiles/cpp.dir/Map.cpp.o CMakeFiles/cpp.dir/TextureManager.cpp.o  -o cpp -F/Library/Frameworks -Wl,-rpath,/Library/Frameworks  -framework  SDL2  -framework Cocoa  -framework  SDL2_image && :
duplicate symbol 'TextureManager::Draw(SDL_Texture*, SDL_Rect, SDL_Rect)' in:
CMakeFiles/cpp.dir/Game.cpp.o
CMakeFiles/cpp.dir/GameObject.cpp.o
duplicate symbol 'TextureManager::Draw(SDL_Texture*, SDL_Rect, SDL_Rect)' in:
CMakeFiles/cpp.dir/Game.cpp.o
CMakeFiles/cpp.dir/Map.cpp.o
duplicate symbol 'TextureManager::Draw(SDL_Texture*, SDL_Rect, SDL_Rect)' in:
CMakeFiles/cpp.dir/Game.cpp.o
CMakeFiles/cpp.dir/TextureManager.cpp.o
ld: 3 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
18:19:20: The process "/Users/m/Qt/Tools/CMake/CMake.app/Contents/bin/cmake" exited with code 1.
Error while building/deploying project cpp (kit: Desktop Qt 5.15.1 clang 64bit)
When executing step "CMake Build"
18:19:20: Elapsed time: 00:01.
TextureManager.cpp:

#include "TextureManager.h"

SDL_Texture* TextureManager::LoadTexture(const char* texture)
{
    SDL_Surface* tempSurface = IMG_Load(texture);
    SDL_Texture* tex = SDL_CreateTextureFromSurface(Game::renderer, tempSurface);
    SDL_FreeSurface(tempSurface);

    return tex;
}

#include "TextureManager.h"

SDL_Texture* TextureManager::LoadTexture(const char* texture)
{
    SDL_Surface* tempSurface = IMG_Load(texture);
    SDL_Texture* tex = SDL_CreateTextureFromSurface(Game::renderer, tempSurface);
    SDL_FreeSurface(tempSurface);

    return tex;
}
void TextureManager::Draw(SDL_Texture * tex, SDL_Rect src, SDL_Rect dest)
{
    SDL_RenderCopy(Game::renderer, tex, &src, &dest);
}

TextureManager.h:

#include "Game.h"

class TextureManager {

public:
    static SDL_Texture* LoadTexture(const char* fileName);
    static void Draw(SDL_Texture* tex, SDL_Rect src, SDL_Rect dest);

};

void TextureManager::Draw(SDL_Texture * tex, SDL_Rect src, SDL_Rect dest)
{
    SDL_RenderCopy(Game::renderer, tex, &src, &dest);
}

#include "Game.h"

class TextureManager {

public:
    static SDL_Texture* LoadTexture(const char* fileName);
    static void Draw(SDL_Texture* tex, SDL_Rect src, SDL_Rect dest);

};

void inline TextureManager::Draw(SDL_Texture * tex, SDL_Rect src, SDL_Rect dest)
{
    SDL_RenderCopy(Game::renderer, tex, &src, &dest);
}

Game.cpp:

#include "Game.h"
#include "TextureManager.h"
#include "GameObject.h"
#include "Map.h"

GameObject* player;
GameObject* enemy;
Map* map;

SDL_Renderer* Game::renderer = nullptr;

Game::Game()
{}
Game::~Game()
{}

void Game::init(const char *title, int xpos, int ypos, int width, int height, bool fullscreen)
{
    int flags = 0;
    if(fullscreen)
    {
        flags = SDL_WINDOW_FULLSCREEN;
    }

    if(SDL_Init(SDL_INIT_EVERYTHING) == 0)
    {
        std::cout << "Subsystems Initialized..." << std::endl;

        window = SDL_CreateWindow(title, xpos, ypos, width, height, flags);
        if(window)
        {
            std::cout << "Window created..." << std::endl;
        }

        renderer = SDL_CreateRenderer(window, -1, 0);
        if(renderer)
        {
            SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
            std::cout << "Renderer created..." << std::endl;
        }

        isRunning = true;
    } else {
        isRunning = false;
    }

    player = new GameObject("../assets/player.png", 0, 0);
    enemy = new GameObject("../assets/enemy.png", 50, 50);
    map = new Map();

}

void Game::handleEvents()
{
    SDL_Event event;
    SDL_PollEvent(&event);
    switch (event.type)
    {
    case SDL_QUIT:
        isRunning = false;
        break;

    default:
        break;
    }

}

void Game::update()
{
    player->Update();
    enemy->Update();
}

void Game::render()
{
    SDL_RenderClear(renderer);

    map->DrawMap();
    player->Render();
    enemy->Render();

    SDL_RenderPresent(renderer);
}

void Game::clean()
{
    SDL_DestroyWindow(window);
    SDL_DestroyRenderer(renderer);
    SDL_Quit();
    std::cout << "Game cleaned..." << std::endl;
}

GameObject.h:

#pragma once
#include "Game.h"

class GameObject {

public:
    GameObject(const char* texturesheet, int x, int y);
    ~GameObject();

    void Update();
    void Render();

private:
    int xpos;
    int ypos;

    SDL_Texture* objTexture;
    SDL_Rect srcRect, destRect;


};

Map.cpp:

#include "Map.h"
#include "TextureManager.h"

int lvl1[20][25] = {
    { 0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
};

Map::Map()
{
    dirt = TextureManager::LoadTexture("../assets/dirt.png");
    grass = TextureManager::LoadTexture("../assets/grass.png");
    water = TextureManager::LoadTexture("../assets/water.png");

    LoadMap(lvl1);

    src.x = src.y = 0;
    src.w = dest.w = 32;
    src.h = dest.h = 32;

    dest.x = dest.y = 0;
}

void Map::LoadMap(int arr[20][25])
{
    for (int row = 0; row < 20; row++)
    {
        for (int column = 0; column < 25; column++)
        {
            map[row][column] = arr[row][column];
        }
    }
}

void Map::DrawMap()
{
    int type = 0;

    for (int row = 0; row < 20; row++)
    {
        for (int column = 0; column < 25; column++)
        {
            type = map[row][column];

            dest.x = column * 32;
            dest.y = row * 32;

            switch (type)
            {
            case 0:
                TextureManager::Draw(water, src, dest);
                break;
            case 1:
                TextureManager::Draw(grass, src, dest);
                break;
            case 2:
                TextureManager::Draw(dirt, src, dest);
                break;
            default:
                break;
            }

        }
    }
}

main.cpp:

#include "Game.h"

Game *game = nullptr;

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

    const int FPS = 60;
    const int frameDelay = 1000 / FPS;

    Uint32 frameStart;
    int frameTime;

    game = new Game();

    game->init("2D Engine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 640, false);

    while (game->running())
    {
        frameStart = SDL_GetTicks();

        game->handleEvents();
        game->update();
        game->render();

        frameTime = SDL_GetTicks() - frameStart;

        if(frameDelay > frameTime)
        {
            SDL_Delay(frameDelay - frameTime);
        }
    }

    game->clean();

    return 0;
}


德雷舍姆的评论已经解决了这一问题

通过在TextureManager.h中添加
inline

#include "Game.h"

class TextureManager {

public:
    static SDL_Texture* LoadTexture(const char* fileName);
    static void Draw(SDL_Texture* tex, SDL_Rect src, SDL_Rect dest);

};

void TextureManager::Draw(SDL_Texture * tex, SDL_Rect src, SDL_Rect dest)
{
    SDL_RenderCopy(Game::renderer, tex, &src, &dest);
}

#include "Game.h"

class TextureManager {

public:
    static SDL_Texture* LoadTexture(const char* fileName);
    static void Draw(SDL_Texture* tex, SDL_Rect src, SDL_Rect dest);

};

void inline TextureManager::Draw(SDL_Texture * tex, SDL_Rect src, SDL_Rect dest)
{
    SDL_RenderCopy(Game::renderer, tex, &src, &dest);
}

或者在TextureManager.h中删除该函数并将其添加到TextureManager.cpp中:

#include "TextureManager.h"

SDL_Texture* TextureManager::LoadTexture(const char* texture)
{
    SDL_Surface* tempSurface = IMG_Load(texture);
    SDL_Texture* tex = SDL_CreateTextureFromSurface(Game::renderer, tempSurface);
    SDL_FreeSurface(tempSurface);

    return tex;
}

#include "TextureManager.h"

SDL_Texture* TextureManager::LoadTexture(const char* texture)
{
    SDL_Surface* tempSurface = IMG_Load(texture);
    SDL_Texture* tex = SDL_CreateTextureFromSurface(Game::renderer, tempSurface);
    SDL_FreeSurface(tempSurface);

    return tex;
}
void TextureManager::Draw(SDL_Texture * tex, SDL_Rect src, SDL_Rect dest)
{
    SDL_RenderCopy(Game::renderer, tex, &src, &dest);
}


您实现了
TextureManager::Draw(
在您的头文件中,它将被多个源文件使用。@drescherjm如何修复它,使它可以被多个源文件使用?
GameObject.cpp
Game.cpp
都包括
TextureManager.h
所以在构建每个
TextureManager::Draw
的实现时,都会出现在每个对象文件中e违反了一个定义规则。您可以将函数标记为内联,以告知链接器允许此操作,或者将实现移动到.cpp文件中。@drescherjm我可以通过执行
void inline TextureManager::Draw使其工作(
但我很好奇如何通过将其实现到.cpp文件中来避免这种情况?这会很困难吗?这会更好吗?这与您在
Map.cpp
Game.cpp
GameObject.cpp
中实现函数的方式相同