c++基类对象的std::vector----派生类的运行方法

Posted

技术标签:

【中文标题】c++基类对象的std::vector----派生类的运行方法【英文标题】:c++ std::vector of base class objects ---- running method of derived class 【发布时间】:2018-02-06 19:32:58 【问题描述】:

我想问一下Java中的“instanceof”之类的东西。我创建了一个简单的继承示例。我的想法是创建一个抽象类 Monster 和孩子 Skeleton 和 Zombie,但是抽象它不起作用,所以我们有 std::vectorBase 类。我将子对象推入向量中。我想调用子类的方法,但是调用的方法是基类的空方法。有没有办法做到这一点?也许在 c++ 编程中我们应该避免这种代码思维,分别使用矢量骨架和矢量僵尸来做?对不起我的英语不好。我希望你能理解我的问题。

 class Monster
        
        public:
            virtual void describe() ;

        ;

    class Skeleton : public Monster
        
        public:
            Skeleton() 

            
            ~Skeleton()
            void describe() override 
                std::cout << "I am skeleton" << std::endl;
            
        ;

    class Zombie : public Monster
        
        public:
            Zombie()
            ~Zombie()
            void describe() override 
                std::cout << "I am Zombie" << std::endl;
            
        ;


        int main(void) 

            std::vector<Monster> potwory;
            potwory.push_back(Skeleton());
            potwory.push_back(Zombie());

            Skeleton sz;
            Zombie z;

            potwory.push_back(sz);
            potwory.push_back(z);

            for (auto i = 0; i < potwory.size(); i++) 
                std::cout << typeid(potwory[i]).name() << std::endl; // each of them is Monster object
                potwory[i].describe();  //here is calling method from base class , I want derived method.  
            

            std::cin.get();
            return 0;

        `

【问题讨论】:

我对你的问题有点困惑。你能试着澄清一下你需要什么吗? C++ 与 Java 的许多不同之处之一是它具有对象切片功能。 Java 避免了它,因为所有引用的行为方式都类似于 C++ 的指针。查看“对象切片”了解更多信息。 你只有一个基类对象的向量。每当你推送一个子类的对象时,你就有object slicing。要使多态性起作用,您需要引用或指针。 使用基类对象类型的std:;vector 会导致在 C++ 中称为对象切片的问题。在 SO 以及更广泛的网络中查找“对象切片”。 好的,谢谢你们。我会读到这个。 【参考方案1】:

如前所述,您遇到了切片问题,因为您只将所有对象的 Monster 部分存储在向量中。 您可以使用 std::vector&lt;Monster*&gt; 或从 c++11 std::vector&lt;std::unique_ptr&lt;Monster&gt;&gt; 开始在向量中存储指向 Monster 的指针/unique_ptr。存储指向实际对象的指针可以减轻切片,因为对象不直接存储在向量中,而只是对堆上实际对象的引用,就像 Java 默认情况下所做的那样。

如果你真的需要价值语义,你应该看看boost.polycollection,但恕我直言,这是一个相当高级的话题。

【讨论】:

【参考方案2】:

感谢您的回答。我无法为您加分以寻求帮助,因为我是 "stack" 上的新手。我读到了这个问题,并写了一个解决方案。如果有人需要这个。

#include <iostream>
#include <vector>
#include <memory>


class Monster

public:
    virtual void describe() ;
    virtual std::unique_ptr<Monster> copy_class()
     
        return std::unique_ptr<Monster>(std::make_unique<Monster>()); 
    

;

class Skeleton : public Monster 

protected:
    const int life = 100;
public:
    Skeleton() 

    
    ~Skeleton()
    void describe() override final 
        std::cout << "I am skeleton" << std::endl;
    
    std::unique_ptr<Monster> copy_class() override 
     
        return std::unique_ptr<Monster>(std::make_unique<Skeleton>()); 
    
;


class Zombie : public Monster

public:
    Zombie()
    ~Zombie()
    void describe() override 
        std::cout << "I am zombie" << std::endl;
    
    std::unique_ptr<Monster> copy_class() override
     
        return std::unique_ptr<Monster>(std::make_unique<Zombie>());
    
;


class UpgradeSkeleton final: public Skeleton

public:
    UpgradeSkeleton()
    ~UpgradeSkeleton() 
    std::unique_ptr<Monster> copy_class() override  return std::unique_ptr<Monster>(std::make_unique<UpgradeSkeleton>()); 
;

int main(void) 

    std::vector<std::unique_ptr<Monster>> monsters;

    Skeleton s;
    Zombie z;
    UpgradeSkeleton us;

    monsters.push_back(std::unique_ptr<Monster>(s.copy_class()));
    monsters.push_back(std::unique_ptr<Monster>(z.copy_class()));
    monsters.push_back(std::unique_ptr<Monster>(us.copy_class()));



    for (auto &p : monsters) 
        p->describe();
    

    std::cin.get();
    return 0;


【讨论】:

以上是关于c++基类对象的std::vector----派生类的运行方法的主要内容,如果未能解决你的问题,请参考以下文章

指向基类的指针的 std::vector 的深拷贝

C++ - 从向量中获取派生类变量

关于C++基类与派生类

C++ 使用带有基类的已删除函数 std::unique_ptr

关于C++基类、派生类的引用和指针

指向派生对象的基类指针的 C++ 排序容器