【问题标题】:How to call a function of an object in a list?如何调用列表中对象的函数?
【发布时间】:2014-05-04 05:08:11
【问题描述】:

我正在开发一个绘画程序。程序将按绘制顺序存储在图形窗口上绘制的元素。我想使用“LIST”来存储绘制的形状。形状有不同的类型,即 allShapes 是父类,而 line 是子类。请告诉我如何在 allShapes 列表中存储一条线并调用它的函数。

示例代码如下:

    class allShapes
    {
     protected:
     int * points; //vertices of the shape
     int color; //color of the shape
     int n; //no. of points
        public:
    //virtual void draw()= 0;
    virtual void draw()
    {

    }
};
       class line:public allShapes
       {
         public:
     line()
     {
    points = new int[4];
    n = 2;
     }
    void draw()
   {
        //Code here
       }
      };


    int main()
   {

int mouse_x, mouse_y;
char key_pressed;
GP142_open();           /* Open and initialize the GP142 Graphics Window    */
list<allShapes> shapes;
int quit = 0;
while (!quit) {

    switch (GP142_await_event(&mouse_x, &mouse_y, &key_pressed)) {

    case GP142_MOUSE:
        if ((mouse_x > -490 && mouse_x<-445) && (mouse_y>305 && mouse_y < 360)) // If user selects the draw line option
        {
            line newLine;
            shapes.push_back(newLine);
            allShapes check = shapes.front();
            check.draw();
        }
        break;
    case GP142_QUIT:
        quit = 1;
        break;
    default:
        break;
    }
}
   }

但是程序没有调用线对象的绘制函数。我也有在 allShapes 中绘制的虚函数。如何调用 check.draw() 在屏幕上画线?

【问题讨论】:

  • 你好像有切片。
  • 您能否建议在上述情况下如何调用派生类函数?
  • 您可以将示例范围缩小到 list&lt;allShapes&gt; shapes; 以及从 line newLine;check.draw(); 的所有内容。其余的似乎是噪音。
  • 如果我对line 派生自allshapes 的假设是正确的,您要么需要一个指针容器或类似的容器(cough 智能指针),要么需要更改设计让客户不必担心,就像this talk
  • 我已经添加了课程代码,你现在可以解释一下吗?

标签: c++ list inheritance polymorphism


【解决方案1】:

对于多态对象,您不能为基类保留足够的存储空间,然后期望能够将任何派生类塞入该空间。当你说:

list<allShapes> shapes;

任何时候你尝试将line 塞入allShapes 对象的空间中,将会发生lineallShapes 部分将被存储,而line 部分将被存储忽略。那么你有一个不是line 的对象,在它上面调用.draw() 不会调用line::draw()。给定对象的动态类型,即allShapes,它将调用正确的draw()方法。

当你说:

allShapes check = shapes.front();
check.draw();

shapes.front() 产生的任何类型都将转换为allShapes。如果您有 lines 的列表,那么它将在此处转换为 allShapes

使用多态一般需要使用指针或引用:

list<unique_ptr<allShapes>> shapes;

现在您可以将行放入此集合中:

shapes.push_back(make_unique<line>()); // make_unique is C++14

这样line 不会被转换成allShapes,所以当虚拟分派根据对象的真实动态类型找到正确的方法时,linedraw() 方法将是用过。

为了访问列表中的对象,您可以使用引用:

allShapes &check = shapes.front();
check->draw();

如果您是从默认使用引用类型的语言(例如 Java 或 C#)转向 C++,那么您确实需要了解 C++ 值类型的工作原理。在那些其他语言中,您到处都使用指针,但语法并不明显。要在 C++ 中使用指针,您必须显式使用特殊的指针语法。

您可能会找到另一个有用的答案:Confused with object arrays in C++

【讨论】:

  • 我试过你的代码,编译器说“unique_ptr”不是模板。
  • @user3566211 unique_ptr 是 C++11 的一部分。我不知道你用的是什么编译器,所以我只是为最新版本的 C++ 编写,因为那是最容易编写的。
  • 我正在使用 Visual Studio Ultimate 2013。
  • @user3566211 那么你的编译器肯定支持它。您必须包含正确的标题:#include &lt;memory&gt;
【解决方案2】:

问题出在这里:

        line newLine;
        shapes.push_back(newLine);
        allShapes check = shapes.front();
        check.draw();

您正在复制线条对象,而不是引用它。 容器shapes 不应包含对象,而应包含指向对象的指针。 如果将线对象复制到allShapes 对象中,allShapes 对象将不会变成line

将容器声明为

list<allShapes*> shapes;

然后写

        line* newLine = new line();
        shapes.push_back(newLine);
        allShapes* check = shapes.front();
        check->draw();

记得delete某处的对象。

【讨论】:

  • @user3566211 如果您使用它,您需要了解如何正确处理动态分配。这不是一件容易正确且异常安全的事情,因此您可能需要阅读更好的方法,例如 R.A.I.I.
猜你喜欢
  • 2017-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-05
  • 2012-11-27
  • 2014-01-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多