【问题标题】:How can I access the members of a subclass from a superclass with a different constructor?如何使用不同的构造函数从超类访问子类的成员?
【发布时间】:2015-09-07 11:04:48
【问题描述】:

我有以下类和 typedef:

class Object

{
protected:
    long int id;
public:
    Object(void);
    ~Object(void) {};
    long int get_id(void);
};

typedef map<string, Object> obj_map;

然后我有了它的孩子:

class Image: public Object

{
private:
    path full_path;
    int x;
    int y;
    img image;
public:
    Image(path p, int x_pos = 0, int y_pos = 0);
    ~Image(void) {};

    void draw(int flags = 0);
    void move_north(float velocity);
    void move_south(float velocity);
    void move_west(float velocity);
    void move_east(float velocity);

    path get_path(void);
    img get_image(void);
    int get_x(void);
    int get_y(void);
    void set_path(path p);
    void set_image(img _image);
    void set_x(int value);
    void set_y(int value);
};

每个对象都存储在这个静态映射 obj_map 中,在一个名为 App 的类中。所以让我们假设我们在键 foo 下有一个对象。我们可以这样打印它的 id:

cout << App::objects.find("foo")->second.get_id() << endl;

现在,假设我已将一个 Image 对象作为值传递给该地图。当我尝试访问它时,我可以正常访问该 id。但是,当我尝试访问 Image 方法时:

cout << App::objects.find("foo")->second.get_x() << endl;

我得到一个:

error: 'class Object' has no member named 'get_x'

那是因为 Object 类实际上没有它。所以,我尝试投射它:

cout << static_cast<Image>(App::objects.find("foo")->second).get_x() << endl;

我明白了:

error: no matching function for call to 'Image::Image(Object&)'

如果我尝试使用 dynamic_cast,我会得到一些可怕的东西......

error: cannot dynamic_cast 'App::objects.std::map<_Key, _Tp, _Compare, _Alloc>::find<std::basic_string<char>, Object, std::less<std::basic_string<char> >, std::allocator<std::pair<const std::basic_string<char>, Object> > >((* & std::basic_string<char>(((const char*)"foo"), (*(const std::allocator<char>*)(& std::allocator<char>()))))).std::_Rb_tree_iterator<_Tp>::operator-><std::pair<const std::basic_string<char>, Object> >()->std::pair<const std::basic_string<char>, Object>::second' (of type 'class Object'

我不明白。构造函数不是继承的。构造函数与它无关。 Image 对象具有完全不同的构造函数,但 它是 一个对象。关键是:我无法创建图像映射,因为最终我的引擎中将有许多对象,并且我希望能够从超类中访问它们。

【问题讨论】:

  • 您的错误是有充分理由的,因为 Object 类没有成员函数 get_x()。继承是一种方式,母亲继承给孩子,而不是相反。
  • 您的地图是使用对象,而不是对象指针。除非使用指针,否则无法获得多态行为。

标签: c++ inheritance constructor subclass superclass


【解决方案1】:

这张地图:

typedef map<string, Object> obj_map;

仅存储 Object 对象。当您尝试将Image 放入时,它会被切掉,并且您会丢失图像中实际上不属于Object 的所有内容。

您似乎正在寻找的行为称为多态性。要激活它,您必须做两件事:

  • 使Object 多态
  • 在地图中存储指向对象的指针

第一部分很简单:在~Object(void)之前添加virtual

对于第二部分,有三种开箱即用的方法:

map<string, Object *>              // 1
map<string, unique_ptr<Object>>    // 2
map<string, shared_ptr<Object>>    // 3

这些选项之间的区别在于您希望如何管理这些对象的生命周期。

如果地图应该拥有对象,请使用 (2) 或 (3)。如果单个对象可能出现在地图中的多个位置,或者您希望能够复制地图,或者地图外部可能存在引用同一对象的引用,请使用(3);否则使用 (2)。

如果您使用 (1),您必须注意对象在地图中的最后一次使用之后是正确的deleted

您可能需要#include &lt;memory&gt; 才能使用智能指针类。

插入一个对象分别如下:

map["foo"] = new Image(....);
map["foo"] = make_unique<Image>(....);
map["foo"] = make_shared<Image>(....);

您实际上可以使用来自new.reset() 的最后两个赋值,但make_ 函数是首选样式。

【讨论】:

    【解决方案2】:

    您应该将 指针 存储到地图中的对象 - 而不是对象(最好是 shared_ptr):

    typedef map<string, shared_ptr<Object>> obj_map;
    obj_map my_map;
    path some_path; // I have no idea what 'path' is and how to use it or even create it
    my_map.insert(make_pair("image1",make_shared<Image>(some_path, 0,0)));
    my_map.insert(make_pair("image2",make_shared<Image>(some_path, 5,5)));
    my_map.insert(make_pair("image3",make_shared<Image>(some_path, 10,10)));
    auto iter = my_map.find("image3");
    auto pImg = dynamic_pointer_cast<Image>(iter->second);
    cout << pImg->get_x() << endl; //this should display '10'
    

    当您将Image 放入定义为map&lt;string, Object&gt; obj_map 的映射中时,您将截断您的Image 对象到Object(基类)。换句话说,您的地图将始终仅存储 Object 元素(而不是Images)。如果您存储指针 - 您存储实际类的对象(您只需将它们存储为指向基类的指针)。因为没有任何内容被截断 - 您始终可以将指针强制转换为派生类并访问其方法。

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-11
      • 2021-09-19
      • 1970-01-01
      • 1970-01-01
      • 2016-05-08
      • 1970-01-01
      • 2012-10-10
      相关资源
      最近更新 更多