如何迭代定义为超类的向量,但调用子类方法

C++ How to iterate over a vector defined as a super class, but call sub class methods?

本文关键字:向量 调用 类方法 超类 何迭代 迭代 定义      更新时间:2023-10-16

我有Java背景,我正试图理解c++中的多态性。具体来说,就是如何在std vector中的一系列子类(由它们的超类定义)上迭代,以便调用特定的方法。我想做的是让子类重写将要调用的超类方法。然而,我不确定如何在c++中做到这一点。

下面是一些代码来帮助提高速度:

    class Tile {
    public:
            virtual void drawTile();
    }
    void Tile::drawTile() {} // not sure if this is needed?
    class Tile_Grass : public Tile {
    public:
            void drawTile();
    }
    void Tile_Grass::drawTile() { ... do stuff  ... }

我想做的是:

    using namespace std;
    for (vector<Tile>::iterator itr = tileVector.begin(); itr != tileVector.end(); ++itr) {
            itr->drawTile(); // draws Tile_Grass, or any other sub class of Tile, but NOT Tile
    }

现在for循环只调用"Tile::drawTile()",但我想让它调用"Tile_Grass::drawTile()",或在"tileVector"向量中的Tile的另一个子类。我做错了什么或者遗漏了什么?提前感谢!

您需要一个Tile*的向量,或者更好的是std::unique_ptr<Tile>;

你应该用指向Tile的指针来声明和填充你的tileVector,而不是Tile对象的副本。

下面是一个完整的Visual Studio 2012示例项目:

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <memory>
class Tile {
public:
       virtual void drawTile();
};
void Tile::drawTile() {} 
class Tile_Grass : public Tile  {
public:
       void drawTile();
};
void Tile_Grass::drawTile() {  std::cout << "Drawing Tile Grass" << std::endl;  }
int _tmain(int argc, _TCHAR* argv[])
{
    typedef std::vector<std::unique_ptr<Tile>> TileVector;
    TileVector vec;
    // add a few Tile_Grass objects
    vec.push_back(std::unique_ptr<Tile>(new Tile_Grass()));
    vec.push_back(std::unique_ptr<Tile>(new Tile_Grass()));
    vec.push_back(std::unique_ptr<Tile>(new Tile_Grass()));
    for (auto itr = vec.begin(); itr != vec.end(); ++itr) {
        (*itr)->drawTile(); // draws Tile_Grass, or any other sub class of Tile, but NOT Tile
    }
    return 0;
}

这将输出Drawing Tile Grass 3次。

相反,如果您定义vector来包含基类Tile的实例,那么存储在vector中的对象将被拼接,即使它们最初是作为派生Tile_Grass对象创建的:

typedef std::vector<Tile> TileValueVector;
TileValueVector vecv;
// add a few Tile_Grass objects
vecv.push_back(Tile_Grass());
vecv.push_back(Tile_Grass());
vecv.push_back(Tile_Grass());
for (auto itr = vecv.begin(); itr != vecv.end(); ++itr)
    itr->drawTile(); // draws Tile

这将打印Drawing Tile 3次,假设:

void Tile::drawTile() { std::cout << "Drawing Tile" << std::endl; } 

在拼接中发生的事情是,只有Tile_Grass的基对象部分被复制到向量元素中,因为您声明希望向量包含该基对象的实例。