2014-01-11 41 views
2

我想在C++中做一种屏幕管理器,但我得到的错误。 我的代码下面我接收与gameScreen.push_back(gameScreenToAdd)发生C++的语法错误

1>screenmanager.cpp(26): error C2664: 'void std::vector<_Ty>::push_back(_Ty &&)' : cannot convert parameter 1 from 'virtualGameScreen' to 'virtualGameScreen *&&' 
1>   with 
1>   [ 
1>    _Ty=virtualGameScreen * 
1>   ] 
1>   Reason: cannot convert from 'virtualGameScreen' to 'virtualGameScreen *' 
1>   No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called 
1> 

错误; 使用gameScreenToAdd添加引用运算符时,会出现访问冲突错误。

ScreenManager.h

void AddScreen(virtualGameScreen); 
void RemoveScreen(virtualGameScreen); 

ScreenManager.cpp

std::vector<virtualGameScreen*> gameScreen; 

void ScreenManager::Initialize(void) 
{ 
    MainMenu menu = MainMenu(); 

    AddScreen(menu); 
} 

void ScreenManager::AddScreen(virtualGameScreen gameScreenToAdd) 
{ 
    gameScreenToAdd.LoadContent(); 

    gameScreen.push_back(gameScreenToAdd); 
} 

所以,我已经打了一下墙上的,我如何可能会解决这个问题有什么建议?

编辑如果我将gameScreen.push_back更改为gameScreen.push_back(new MainMenu()),游戏运行; buut这不是真的我多么希望函数工作

+1

你已经声明了一个'std :: vector'来存放_pointers_,但是你正试图'push_back()'一个_object_。你需要决定哪一个是你真正想要的。 – Blastfurnace

回答

3

,编译器做的第一件事就是告诉你在哪里出现问题:

1>screenmanager.cpp(26) 

它还告诉你的问题主要是什么:

Reason: cannot convert from 'virtualGameScreen' to 'virtualGameScreen *' 

这样的 - 我在你的代码正在提供一个“virtualGameScreen”对象实例,该实例正在等待一个指针(由*表示)。它在第26行。错误的其他部分表明这是对push_back的调用。让我们看看第26行:

gameScreen.push_back(gameScreenToAdd); 

是的 - 你打电话的push_back,而你通过它gameScreenToAdd,这是virtualGameScreen类型。该push_back电话是从这个载体:

std::vector<virtualGameScreen*> gameScreen; 

你的矢量预计指针,所以预计的push_back载体。

但是:你不能做到这一点:

gameScreen.push_back(&gameScreenToAdd); 

因为gameScreenToAdd是一个临时的函数的变量 - 当你调用AddScreen,原来的变量被复制到一个新的,临时virtualGameScreen为的寿命函数调用。这意味着当程序离开AddScreen时,您推送的地址将不再存在的屏幕(内存仍然存在,但它已被释放,并且计算机现在将继续使用它以用于其他原因)。

你需要做的就是改变AddScreen来取指针。

void ScreenManager::AddScreen(virtualGameScreen* gameScreenToAdd) 
{ 
    gameScreenToAdd.LoadContent(); 

    gameScreen.push_back(gameScreenToAdd); 
} 

不幸的是,这会让您打开代码的另一个问题。

void ScreenManager::Initialize(void) 
{ 
    MainMenu menu = MainMenu(); 

    AddScreen(menu); 
} 

该函数创建一个临时的本地MainMenu对象,并且其生命周期为Initialize。然后它创建第二个临时MainMenu并将其复制到菜单。

如果你写

AddScreen(&menu); 

它会工作,但它会一个临时的实例的地址传递给AddScreen。

只要程序流程离开“Initialize()”函数,您的值就会消失。

它看起来像你可能有一些像Java或C#之类的东西的经验,并试图将以前的知识应用于C++。

你需要的是一个成员变量来存储ScreenManager实例生命期的“Menu”。

选项1:只需使用类成员变量。

class ScreenManager 
{ 
    MainMenu m_menu; 

public: 
    ScreenManager() 
     : m_menu() // initialize menu while we are initializing. 
    {} 

    void Initialize() 
    { 
     AddScreen(&m_menu); 
    } 
// ... 
}; 

如果你真的想用一个指针,你不妨做到以下几点:

class ScreenManager 
{ 
    MainMenu* m_menu; 

public: 
    ScreenManager() 
     : m_menu(nullptr) // make sure it's null as soon as the object is created 
    {} 

    void Initialize() 
    { 
     m_menu = new MainMenu(); 
     AddScreen(m_menu); 
    } 

    // but now we have to make sure it is released when we go away 

    ~ScreenManager() 
    { 
     if (m_menu) 
     { 
      delete m_menu; 
      m_menu = nullptr; 
     } 
    } 
}; 

方案3:使用C++容器管理指针的一生为你,无论是标准::的unique_ptr或std :: shared_ptr的

---- ----编辑

看到你,我在写这篇而做出的编辑,这是一个更清晰一点你想要做什么。你可能需要的是更多的东西是这样的:

std::vector<std::unique_ptr<virtualGameScreen>> gameScreen; 

考虑以下几点:

现场演示:http://ideone.com/7Th2Uk

#include <iostream> 
#include <vector> 

class Foo { 
    const char* m_name; 
public: 
    Foo(const char* name) : m_name(name) { std::cout << "Foo " << m_name << '\n'; } 
    ~Foo() { std::cout << "~Foo " << m_name << '\n'; } 
}; 

int main() { 
    std::vector<Foo*> foos; 
    Foo foo("foo"); 
    foos.push_back(new Foo("new")); 

    return 0; 
} 

注意,第二FOO永远不会释放。

Foo foo 
Foo new 
~Foo foo 

std::unique_ptr是一个指针,容器对象,当对象过期,这将删除对象。这使得它适合于喜欢的std ::向量容器使用

#include <iostream> 
#include <vector> 
#include <memory> // for std::unique_ptr 

class Foo { 
    const char* m_name; 
public: 
    Foo(const char* name) : m_name(name) { std::cout << "Foo " << m_name << '\n'; } 
    ~Foo() { std::cout << "~Foo " << m_name << '\n'; } 
}; 

int main() { 
    std::vector<std::unique_ptr<Foo>> foos; 
    Foo foo("foo"); 
    foos.emplace_back(new Foo("new")); 

    return 0; 
} 

两个对象都得到清理:

Foo foo 
Foo new 
~Foo foo 
~Foo new 

现在你不需要你m_menu可言,你可以简单地调用AddScreen与一个'新的MainMenu()'和指针将被添加到矢量,以便当矢量超出范围时,将发生适当的清理。

Menu* menu = new MainMenu(); 
AddScreen(menu); 

AddScreen(new MainMenu()); 

在理论上是什么你应该做的是确保分配直接进入一个的unique_ptr对象,这样有没有窗口,它得到泄露,但教学使用的std :: unique_ptr超出了这个答案的范围。 http://msdn.microsoft.com/en-us/library/hh279676.aspx,http://www.drdobbs.com/cpp/c11-uniqueptr/240002708

+0

谢谢:)这一直非常有帮助。我不太喜欢任何解决方案,因为我希望将所有的游戏画面存储在一个列表或矢量中,但是您肯定会给我选择继续。 :D – Anthony

+0

是的 - 我发现你的编辑问题,并增加了我的答案。希望有所帮助。 – kfsone

+0

最后,在帖子中的代码中的问题是你的对象是临时的,并且向量中存储指针会给你带来负担,以确保你移除的任何东西也会释放。你可以通过使用智能指针(std:unique_ptr,std:shared_ptr等)来解决这个问题,它可以使一些函数指纹有点毛发,但最终可以在你没有的错误和你不知道的问题上得到回报不必担心:) – kfsone

1

在预C++ 11的代码,你可能有这样的事情:

std::vector<virtualGameScreen*> gameScreen; 

void ScreenManager::Initialize(void) 
{ 
    AddScreen(new MainMenu); 
} 

void ScreenManager::AddScreen(virtualGameScreen *gameScreenToAdd) 
{ 
    gameScreenToAdd->LoadContent(); 

    gameScreen.push_back(gameScreenToAdd); 
} 

但你必须有一些方法来确保对象被删除。

用C++ 11,你可能会想拥有自动记忆管理:

std::vector<std::unique_ptr<virtualGameScreen>> gameScreen; 

void ScreenManager::Initialize(void) 
{ 
    AddScreen(std::unique_ptr<MainMenu>(new MainMenu)); 
} 

void ScreenManager::AddScreen(std::unique_ptr<virtualGameScreen> gameScreenToAdd) 
{ 
    gameScreenToAdd->LoadContent(); 

    gameScreen.emplace_back(std::move(gameScreenToAdd)); 
} 
0

那是因为你没有提供的指针向量(gameScreen),以及有关代码中的另一个问题是即:参数将生成一个临时对象,如果只是放置它的地址,应用程序可能会崩溃。