C ++通过多个函数返回类对象

时间:2013-12-09 16:55:31

标签: c++ function visual-c++ pointers

我正在尝试通过多个函数传递自定义对象(TextureInfos)。

电话是:

TextureManager::Instance()->getTextureInfos("TEST",0)

TextureManager.cpp

TextureInfos& TextureManager::getTextureInfos(std::string key, int id) 
{
    TextureSet textureSet = textureSets[key];

    return textureSet.getTextureInfos(id);
}

TextureSet .cpp

TextureInfos& TextureSet::getTextureInfos(int id) 
{   
    sf::Texture texture;
    sf::IntRect rect;

    if (id < tileCount) {
        int x = (id % maxCol) * tileWidth;
        int y = (id / maxCol) * tileHeight;
        rect.left = x;
        rect.top = y;
        rect.width = tileWidth;
        rect.height = tileHeight;
    }

    TextureInfos *textureInfos = new TextureInfos(texture,rect);

    return textureInfos;
}

我是C ++的新手,我想我错过了与运营商“&amp;”的东西。和“*”等因为这段代码暂时不起作用......

有任何帮助吗? 非常感谢。

编辑:

好的,所以这段代码的目的是在流程结束时获得一个TextureInfos对象。为此,我需要从TextureManager调用getTextureInfos方法,该方法也从getTextureInfos调用TextureSet

这是TextureManager.cpp

的完整代码
#include "TextureManager.h"
#include <iostream>
#include <fstream>

TextureManager TextureManager::m_TextureManager;
const std::string basePath="Assets/Graphics";

#pragma region Constructor
TextureManager::TextureManager()
{
    textureSets.clear();
}

TextureManager::~TextureManager()
{

}
#pragma endregion

#pragma region Textures management

// Charge un set de texture a partir d'un nom de fichier
void TextureManager::LoadTextureset(std::string fileName,std::string key) {

    TextureSet textureSet;
    textureSet.init(basePath + fileName, key);

    textureSets[key] = textureSet;
}

// Récupère une texture de la liste
TextureInfos TextureManager::getTextureInfos(std::string key, int id) 
{
    TextureSet textureSet = textureSets[key];

    return textureSet.getTextureInfos(id); // HERE I GET AN ERROR
}

#pragma endregion

最后评论的行是我收到错误的地方:

no suitable user-defined conversion from "TextureInfos" to "TextureInfos" exists.

对于TextureSet.cpp:

#include "TextureSet.h"
#include <iostream>
#include <fstream>
#include "RapidXML\rapidxml.hpp"
#include "Debug.h"

const std::string basePath="Assets/Graphics";

using namespace rapidxml;

#pragma region Constructor
TextureSet::TextureSet()
{

}

TextureSet::~TextureSet()
{

}
#pragma endregion

void TextureSet::init(std::string l_filePath,std::string l_key)
{
    filePath = l_filePath;
    key = l_key;

    // On détermine les URLs des fichiers
    std::string setDescriptorPath = filePath + ".xml";
    std::string setTilesetPath = filePath + ".png";

    // On charge la texture
    if (!textureSet.loadFromFile(setTilesetPath))
        throw "ça load pas";

    // On lis le xml
    std::ifstream xmlDescriptor(setDescriptorPath);
    if(!xmlDescriptor)
        throw "Could not load tileset: " + setDescriptorPath;

    std::string xmlDescriptorContents;
    {
        std::string line;
        while(std::getline(xmlDescriptor, line))
            xmlDescriptorContents += line;
    }

    std::vector<char> xmlData = std::vector<char>(xmlDescriptorContents.begin(), xmlDescriptorContents.end());
    xmlData.push_back('\0');

    //Create a parsed document with &xmlData[0] which is the char*
    xml_document<> doc;
    doc.parse<parse_no_data_nodes>(&xmlData[0]);

    //Get the root node
    xml_node<>* root = doc.first_node();
    xml_node<>* imagefile = root->first_node("params");

    maxRow = atoi(imagefile->first_attribute("maxRow")->value());
    maxCol = atoi(imagefile->first_attribute("maxCol")->value());
    tileWidth = atoi(imagefile->first_attribute("tileWidth")->value());
    tileHeight = atoi(imagefile->first_attribute("tileHeight")->value());
    tileCount = atoi(imagefile->first_attribute("tileCount")->value());
}

TextureInfos TextureSet::getTextureInfos(int id) 
{   
    sf::Texture texture;
    sf::IntRect rect;

    if (id < tileCount) {
        int x = (id % maxCol) * tileWidth;
        int y = (id / maxCol) * tileHeight;
        rect.left = x;
        rect.top = y;
        rect.width = tileWidth;
        rect.height = tileHeight;
    }

    TextureInfos textureInfos(texture,rect);

    return textureInfos;
}

TextureInfos.h

#include <unordered_map>
#include <vector>
#include <SFML\Graphics.hpp>
#include <string>

class TextureInfos
{

private:

protected:

public:
    TextureInfos(sf::Texture& l_texture, sf::IntRect l_textureRect);
    ~TextureInfos();

    sf::Texture& texture;
    sf::IntRect textureRect;
};

4 个答案:

答案 0 :(得分:1)

不,它不起作用,因为它甚至没有编译。它不编译的原因是因为您尝试将指针作为引用返回。指针和引用是两回事。

要快速,简单和肮脏的修复,请将返回类型从TextureInfos&更改为TextureInfos*


上面提到的快速修复是“脏”的,因为在使用代码时会出现内存泄漏(使用new分配内存但不释放内存)。

这可以通过两种方式解决:按值返回 而不是使用指针/引用。或者使用智能指针,例如std::unique_ptr

答案 1 :(得分:1)

如果你可以避免使用动态内存分配,只需编辑你的TextureSet::getTextureInfos以按值返回一个新的堆栈对象(如果你担心效率,请注意会有一个返回值优化):

TextureInfos TextureSet::getTextureInfos(int id) 
{   
    // ...
    return TextureInfos(texture, rect);
}

否则,如果您确实需要动态分配,请使用std::shared_ptr以避免内存泄漏:

std::shared_ptr<TextureInfos> TextureSet::getTextureInfos(int id) 
{   
    // ...
    return std::make_shared<TextureInfos>(texture, rect);
}

答案 2 :(得分:0)

根据你的对象命名,我假设你想在TextureSet中有一组对象。因此,我建议在您的Object中添加一个私有变量,并针对此对象测试新的get请求。然后,您可以安全地返回对成员的引用。

答案 3 :(得分:0)

有人认为看起来非常令人担忧的是TextureInfos引用包含在纹理中,并从传递的引用中构造一个。

TextureInfos(sf::Texture& l_texture, sf::IntRect l_textureRect);

sf::Texture& texture;
sf::IntRect textureRect;

假设构造函数执行类似这样的操作

TextureInfos(sf::Texture& l_texture, sf::IntRect l_textureRect) : 
  texture(l_texture),
  textureRect(l_textureRect)
{
}

...然后你正在进入一个充满痛苦的世界。查看GetTextureInfos()以了解原因: -

TextureInfos& TextureSet::getTextureInfos(int id) 
{   
    sf::Texture texture;
    sf::IntRect rect;

    ...

    TextureInfos *textureInfos = new TextureInfos(texture,rect);

    return textureInfos;
}

忽略这可能会泄漏返回对象的明显问题,您遇到的主要问题是返回的对象保留对texture的引用 - 但texture已超出范围,因此不再有效!

我不能提出一个简单的解决方案 - 但您需要确保您了解您正在创建的对象的生命周期管理和所有权问题。智能指针(并返回整个对象而不是引用)通常是其中的关键部分。