【问题标题】:C++ Inserting a class into a map containerC ++将类插入地图容器
【发布时间】:2011-01-17 21:27:30
【问题描述】:

我有一个 C++ 映射,我希望输入我的类作为值,并输入一个字符串作为键。 当我尝试时,我得到一个错误'Scene_Branding' : illegal use of this type as an expression 我非法使用这种类型作为表达式,我似乎无法找出原因。这是一些代码。

 string CurrentScene = "Scene_Branding";
 map<string, Scene> Scenes;
 Scenes.insert(std::make_pair("Scene_Branding", Scene_Branding));  //<-- Illegal Error parameter 2

这里是场景品牌标题..

#ifndef Scene_Branding_H
#define Scene_Branding_H

#include "Scene.h"
#include <iostream>
#include <string>


class Scene_Branding : Scene
{
public:
 Scene_Branding();
 ~Scene_Branding();
 void Draw();
};

#endif

这里是场景标题..

#ifndef Scene_H
#define Scene_H

#include <iostream>
#include <string>

class Scene
{
public:
 Scene();
 ~Scene();
 virtual void Draw();

};

#endif

这里有 cpp 文件。

场景 cpp。

#include "Scene.h"

Scene::Scene()
{

}
Scene::~Scene()
{

}
void Scene::Draw(){
 std::cout << "Hey";
}

Scene_Branding cpp

#include "Scene_Branding.h"

Scene_Branding::Scene_Branding()
{

}

Scene_Branding::~Scene_Branding()
{

}

void Scene_Branding::Draw()
{
 std::cout << "Drawing from Scene_branding";
}

【问题讨论】:

  • 两个答案都是正确的,指出您需要 Scene_Branding 的实例而不仅仅是类型。另一个提示使您的基类析构函数虚拟
  • 你真的要使用私有继承吗?

标签: c++ class inheritance map


【解决方案1】:

首先,不要将对象本身存储在地图中,而是存储指向对象的指针。

其次,您需要将 Scene_Branding 的实例提供给 std::make_pair,而不是类本身。

编辑: 以下是存储指针的方法:

 string CurrentScene = "Scene_Branding";
 map<string, Scene*> Scenes;
 Scenes.insert(std::make_pair("Scene_Branding", new Scene_Branding()));

但是,既然你问了这类问题,我建议你阅读一本好的 c++ 书籍,以进一步掌握指针等概念。

【讨论】:

  • 只要对象的类是最终的,就可以存储对象。
  • 啊哈,我试过了,但我错误地放置了 Scene_Branding .. 无论如何,谢谢。
  • @kennytm 你能澄清一下吗。什么意思“只要对象的类是最终的?你的意思是final keyword?为什么这个最终会做?
  • @IvanTalalaev "final" 表示Scene 类没有子类。如果有子类,那么使用map&lt;string, Scene&gt; 可能会导致对象切片。 final 类可以防止这种情况。
【解决方案2】:

试试:

Scenes.insert(std::make_pair("Scene_Branding", Scene_Branding()));

【讨论】:

  • 这行得通,但代码与预期不符,cout 正在输出嘿,而不是从 Scene_Branding 绘图.. 嗯,但感谢您的修复。
  • 这是因为地图中存储了 Scene 的实例,而不是 Scene_Branding 的实例。这称为对象切片,简而言之,它会导致您丢失在 Scene_Branding 中声明的信息。存储指针不会导致此问题。
  • 我将如何处理指针?我似乎只是得到诸如错误 C2664 之类的错误:'Scene::Scene(const Scene &)' : cannot convert parameter 1 from 'Scene_Branding (__cdecl *const )(void)' to 'const Scene &'
  • -1 因为切片错误。我想你没有看到 OP 想要一个多态对象的容器。 :-)
【解决方案3】:

我认为你不想这样做。

  1. C++ 中没有运行时类型映射,您存储的是对象,而不是类型。
  2. 您不能在 STL 容器中存储多态类型,如果您愿意,请改用 boost::ptr_map

所以,“新”代码:

class Scene
{
public:
  virtual ~Scene();                  // Virtual Destructor, it's a base class
  virtual Scene* clone() const = 0;  // Polymorphic construction
private:
  // whatever you wish
};

class Scene_Branding: public Scene
{
public:
  virtual Scene_Branding* clone() const { return new Scene_Branding(); }
};

以及存储这些的新方法:

const std::string SceneBrandingKey = "Scene_Branding";

typedef boost::ptr_map<std::string, Scene> scenes_type;

scenes_type Scenes;
Scenes.insert(SceneBrandingKey, new Scene_Branding());

你可以这样使用它:

Scenes["Scene_Branding"].process(); // Note: use '.' not '->'

Boost Pointer Container 的好处在于它适用于多态类型,具有异常安全性和所有功能,但它模仿了 STL 的行为/接口,因此您不会迷路 :)

【讨论】:

  • 我认为 OP 是一个小新手,还需要深入研究。
  • 我不确定,但恕我直言,而不是虚拟 Scene_Branding* clone() const 应该是虚拟 Scene* clone() const ;-)
  • 有趣的是,每个人都认为 C++ 新手需要学会以容易出错的手动方式做事,然后才能使用让生活更轻松的库。
  • +1 OP 了解手动内存管理的陷阱后,会开始欣赏 shared_ptr 和 ptr_container。
  • 当然,让生活更轻松的东西更好,但是,为了有效地使用高级的东西,一个人必须了解低级的东西,你不觉得吗?不要把兰博基尼送给新司机。
【解决方案4】:

当使用通用地图容器时,您需要在类中使用指针,结果可能是您的类中的新对象是空的...使用指针有效!

std::map<std::string, Type*> map_;

插入

map_["key"] = *Type;

注意:如果未设置编译器的 -fpermisive 标志,则在 map_ 容器中插入时需要传递 *Type 而不是 const。

最好的问候,

哈维尔,

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-31
    • 1970-01-01
    • 2019-07-18
    相关资源
    最近更新 更多