【问题标题】:Cannot access private member in class sf::NonCopyable. Where is the copy? C++无法访问类 sf::NonCopyable 中的私有成员。副本在哪里? C++
【发布时间】:2014-12-02 19:48:16
【问题描述】:

使用 SFML 2.1

我决定制作一个包含我的音频文件的对象。但是,当我运行测试时,出现以下错误:

错误 C2248:“sf::NonCopyable::NonCopyable”:无法访问在“sf::NonCopyable”类中声明的私有成员

我在 SFML 网站上查找了有关此错误的一些信息,它指出我无法复制继承 sf::NonCopyable 的对象(我认为)。这些对象可能是我即将展示的 sf::Sound 和 sf::Music。真正的问题是:这个副本是在哪里制作的,我该如何修复它?

音频类

struct Audio {
    std::map<std::string, sf::Sound> sounds;
    std::map<std::string, sf::Music> musics;

    Audio() : sounds(),
        musics(){}


    void addSound(sf::Sound& s, sf::SoundBuffer& sb, std::string key){
        s.setBuffer(sb);
        sounds.insert(std::pair<std::string, sf::Sound>(key, s));
    }
    void addSound(sf::Sound& s, std::string key){
        sounds.insert(std::pair<std::string, sf::Sound>(key, s));
    }
    void addMusic(sf::Music& m, std::string key){
        musics.insert(std::pair<std::string, sf::Music>(key, m));
    }
    sf::Sound& getSound(std::string key){
        return sounds[key];
    }
    sf::Music& getMusic(std::string key){
        return musics[key];
    }
};

加载声音方法

void loadSounds(Audio& audio){
    sf::Music backgroundMusic;
    sf::Sound eating;
    sf::SoundBuffer sb_eating;
    sf::Sound moving;
    sf::SoundBuffer sb_moving;
    sf::Sound losing;
    sf::SoundBuffer sb_losing;
    sf::Sound begin;
    sf::SoundBuffer sb_begin;

    if (!backgroundMusic.openFromFile("backgroundmusic.wav"))
        std::cerr << "Error opening \"backgroundmusic.wav\"" << std::endl;
    if (!sb_eating.loadFromFile("eatingsfx.wav"))
        std::cerr << "Error opening \"eatingsfx.wav\"" << std::endl;
    if (!sb_moving.loadFromFile("movingsfx.wav"))
        std::cerr << "Error opening \"movingsfx.wav\"" << std::endl;
    if (!sb_losing.loadFromFile("losingsfx.wav"))
        std::cerr << "Error opening \"losingsfx.wav\"" << std::endl;
    if (!sb_begin.loadFromFile("beginsfx.wav"))
        std::cerr << "Error opening \"beginsfx.wav\"" << std::endl;

    eating.setBuffer(sb_eating);
    moving.setBuffer(sb_moving);
    losing.setBuffer(sb_losing);
    begin.setBuffer(sb_begin);

    audio.addMusic(backgroundMusic, std::string("backgroundMusic"));
    audio.addSound(eating, std::string("eating"));
    audio.addSound(moving, std::string("moving"));
    audio.addSound(losing, std::string("losing"));
    audio.addSound(begin, std::string("begin"));
}

主要方法

int main(){
    /*Initialize the objects*/
    Snake snake = Snake();
    Audio& audios = Audio();
    sf::Text textCount;
    Apple apple(0, 0);
    apple.locateApple();
    sf::RenderWindow window(sf::VideoMode(windowWidth, windowHeight), "SFML Application" );
    /*Load the audio*/
    loadSounds(audios);

    audios.getMusic("backgroundMusic").setVolume(10);
    audios.getMusic("backgroundMusic").setLoop(true);
    audios.getMusic("backgroundMusic").setVolume(25);


    /*Load the font*/
    sf::Font font;
    if (!(font.loadFromFile("arial.ttf")))
        std::cout << "Error loading fonts" << std::endl;
    /*Create the text*/
    textCount.setFont(font);
    textCount.setString(std::string("points: ") + std::to_string(points));
    textCount.setColor(sf::Color::Red);
    textCount.setCharacterSize(20);
    textCount.setPosition(windowWidth / 2 - (textCount.getString().getSize()*(textCount.getCharacterSize() / 5)), textCount.getCharacterSize() - 5);
    textCount.setStyle(sf::Text::Bold);

    window.draw(textCount);

    /*Set Framerate fps*/
    window.setFramerateLimit(10);

    /*MAIN GAME LOOP*/
    counterTick = 1;

    audios.getSound("begin").play();
    audios.getMusic("backgroundMusic").play();
    while (inGame)
    {
        std::string counter = std::to_string(counterTick);
        std::cout << "Tick: " + counter << std::endl;

        window.clear(sf::Color::Black);
        sf::Event event;
        while (window.pollEvent(event)){
            if (event.type == sf::Event::Closed)
                window.close();
        }
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Escape)) break;
        /*Call Updates*/
        snake.input();
        snake.checkReals();
        snake.moveUpdate();
        audios.getSound("moving").play();

        /*Call Collisions*/
        std::cout << "     Outside Collision Loop " << std::endl;
        checkApple(snake, apple, audios.getSound("eating"));
        checkBoundary(snake);

        /*Call Draw*/
        std::vector<sf::RectangleShape> shapearray = snake.draw();
        for (int i = shapearray.size() - 1; i >= 0; i--){
            window.draw(shapearray[i]);
        }
        window.draw(textCount);
        window.draw(apple.draw());
        window.display();

        counterTick++;

    }
    audios.getSound("losing").play();
    audios.getMusic("backgroundMusic").stop();
    std::system("PAUSE");//bad practice, debuggin purposes
    return 0;
}

【问题讨论】:

  • std::pair 制作一个副本,然后将其插入到地图中创建另一个。也许您想改用std::unique_ptr 或std::shared_ptr?
  • 您使用的是 C++ 11 吗?你也许可以使用新的移动语法——基本上改变你的 addSound、addMusic 等函数来获取 Sound&& 等。
  • @Bash Music 似乎是这里涉及的唯一不可复制的对象(因为它包含 sf::Thread)。您可能必须使用指向sf::Music 的指针。由于 SFML 的人没有实现移动构造器,因此它几乎是您唯一的选择。哦,副本是在这一行制作的 musics.insert(std::pair&lt;std::string, sf::Music&gt;(key, m));

标签: c++ sfml


【解决方案1】:

就像已经提到的 cmets,sf::Music 不能被复制。您最好的选择可能是将其包装在 std::unique_ptr 中,因为您不需要共享所有权。

由于您在之前的问题中说过您正在为学校执行此操作,因此我将向您展示如何使用 C++11 执行此操作

#include <string>
#include <map>
#include <memory>

//non copyable and non movable like sf::Music
struct NonCopyable
{
    NonCopyable() {};
    NonCopyable(const NonCopyable &&other) = delete;
    NonCopyable(const NonCopyable &other) = delete;
    void randomFunc(){}
};

struct MapHolder
{
    std::map<std::string, std::unique_ptr<NonCopyable>> container;

    void addElement(const std::string &key, std::unique_ptr<NonCopyable> value)
    {
        //std::move is necessary here, compiler error without it, since
        //unique_ptr<T> is non-copyable but can be moved just fine
        container.insert({key , std::move(value)});
    }

    NonCopyable &get(const std::string &key)
    {
        //using container[key] will create a new NonCopyable if none is found
        //this will however throw an exception if key is not in the map
        return *container.at(key);  
    }

    //probably not necessary in this case but this is so that you can get a 
    //const NonCopyable elements from a "const MapHolder", without this, 
    //calling ".get" on a "const MapHolder" would be an error
    const NonCopyable &get(const std::string &key) const
    {
        return *container.at(key);
    }

};


int main()
{
    MapHolder holder;

    auto myInstance = std::make_unique<NonCopyable>();
    //if make_unique is not supported on your compiler use this:
    //auto myInstance = std::unique_ptr<NonCopyable>(new NonCopyable());

    //this is how you access members of NonCopyable
    myInstance->randomFunc();

    //again, the move here is necessary, since std::unique_ptr is non-copyable
    //after this line "myInstance" is invalid
    holder.addElement("test", std::move(myInstance));

    //doing this is illegal now, since myInstance is now moved
    //it should be noted that std::move was only a cast, the actual moving
    //happened because "addElement" took the unique_ptr by value and
    //thereby transferred the ownership during construction of its local parameter
    //myInstance->randomFunc();

    //this is ok
    holder.get("test").randomFunc();

    //this is fine too
    NonCopyable &local_ref = holder.get("test");
    local_ref.randomFunc();  

    return(0);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-25
    相关资源
    最近更新 更多