简体   繁体   English

我想要一个派生类指针的向量作为基类指针

[英]I want a vector of derived class pointers as base class pointers

In C++, the vector class stores an array of objects. 在C ++中,vector类存储一个对象数组。 In this case, I am storing pointers to derived class objects (Dogs). 在这种情况下,我存储指向派生类对象(Dogs)的指针。 At some point, I want to treat this vector as pointers to objects of the base class (Animals). 在某些时候,我想将此向量视为指向基类(动物)对象的指针。 This is the "right"/non controversial way right? 这是“正确”/无争议的方式吗? Why can't I do this? 为什么我不能这样做?

#include <vector>
using namespace std;

class Animal { }; 
class Dog : public Animal { };

int main(int argc, char *argv[]) {
    vector<Dog*> dogs;
    dogs.push_back(new Dog());
    dogs.push_back(new Dog());
    vector<Animal*> animals = dogs; // This doesn't seem to work.

    // This is really what I want to do...
    vector<Animal*> all_animals[] = {dogs, cats, birds};
}

The error: 错误:

Untitled.cpp:11:18: error: no viable conversion from 'vector<class Dog *>' to 'vector<class Animal *>'
    vector<Animal*> animals = dogs;
                    ^         ~~~~
/usr/include/c++/4.2.1/bits/stl_vector.h:231:7: note: candidate constructor not viable: no known conversion from 'vector<Dog *>' to 'const std::vector<Animal *, std::allocator<Animal *> > &' for 1st argument
  vector(const vector& __x)
  ^

There is a copy constructor for a std::vector but it requires you to copy the exact same type of vector. std::vector有一个复制构造函数,但它要求你复制完全相同类型的向量。 Fortunately, there is another constructor which takes a pair of iterators and adds all the elements in the range, so you can do this: 幸运的是,还有另一个构造函数,它接受一对迭代器并添加范围内的所有元素,因此您可以这样做:

vector<Animal*> animals(dogs.begin(),dogs.end());

This creates a new vector of Animal pointers by iterating through each Dog pointer. 这通过迭代每个Dog指针创建一个Animal指针的新向量。 Each Dog pointer is converted to an Animal pointer as it goes. 每个Dog指针都会转换为Animal指针。

Here is a more complete example (using C++11): 这是一个更完整的例子(使用C ++ 11):

#include <vector>

struct Animal { };

struct Dog : Animal { };

struct Cat : Animal { };

struct Bird : Animal { };

int main(int,char**)
{
  Dog dog1, dog2;
  Cat cat1, cat2;
  Bird bird1, bird2;
  std::vector<Dog *> dogs = {&dog1,&dog2};
  std::vector<Cat *> cats = {&cat1,&cat2};
  std::vector<Bird *> birds = {&bird1,&bird2};
  std::vector<std::vector<Animal *>> all_animals = {
    {dogs.begin(),dogs.end()},
    {cats.begin(),cats.end()},
    {birds.begin(),birds.end()}
  };
}

You can do what you really want to do with no problems at all! 你可以毫无问题地做你真正想做的事! That is, simply do: 也就是说,只需:

class Animal {
   public:
      std::string GetNoise() const = 0;
};
class Dog : public Animal {
   public:
      std::string GetNoise() const { return "Bark!"; }
};
class Cat : public Animal {
   public:
      std::string GetNoise() const { return "Meow"; }
      bool        LikesSleeping() const { return true; }
};

Dog* d = new Dog;
Cat* c = new Cat;
vector<Animal*> all_animals;
all_animals.push_back(d, c);

// then, later...

// this will print "Bark!"
std::cout << all_animals[0]->GetNoise() std::endl;

// if you know the type somehow
Cat* x = dynamic_cast<Cat*>(all_animals[1]);
const bool y = x->LikesSleeping();

The reason that your code didn't work the way you expect is that: std::vector<Dog*> is a totally different class from std::vector<Animal*> . 你的代码没有按照你期望的方式工作的原因是: std::vector<Dog*>是一个与std::vector<Animal*>完全不同的类

In other words, Dog inherits from Animal, yes, but a std::vector<X> does not inherit from std::vector<Y> -- no matter how X and Y are related! 换句话说,Dog继承自Animal,是的,但是std::vector<X>不会继承自std::vector<Y> - 无论X和Y如何相关!

Templates don't give the vector much intelligence; 模板不会给矢量带来太多的智能; they just define a new class. 他们只是定义了一个新类。 You can think of it this way: 你可以这样想:

class vectorOfDogs {
    Dog* myDogs;
    //...
}

class vectorOfAnimals {
    Animal* myAnimals;
    //...
}

Does vectorOfDogs inhert from vectorOfAnimals ? 是否vectorOfDogs从inhert vectorOfAnimals Clearly not! 显然不是! But all that's been done is changing the name of the class from std::vector<Dog*> to vectorOfDogs . 但是所做的就是将类的名称从std::vector<Dog*>更改为vectorOfDogs

The accepted solution is fine, but has one big drawback: It maintains copies of the contents of the vectors in question. 接受的解决方案很好,但有一个很大的缺点:它保留了相关载体内容的副本。 Any time one of the vectors is updated, we need to update the redundant data as well to keep global state consistent. 任何一个向量更新时,我们都需要更新冗余数据以保持全局状态一致。 Not being very fond of, decided to try to get around this issue (unfortunately needed to discover that this requires quite some work...): 不是很喜欢,决定试图解决这个问题(不幸的是需要发现这需要相当多的工作......):

class AllAnimals
{
    struct Wrapper
    {
        virtual ~Wrapper() { }
        virtual Animal* begin() = 0;
        virtual Animal* end() = 0;
    };

    template <typename T>
    struct SpecificWrapper : Wrapper
    {
        T& animals;
        SpecificWrapper(T& animals)
                : animals(animals)
        { }
        Animal* begin() override
        {
            return *animals.begin();
        }
        Animal* end() override
        {
            return *animals.end();
        }
    };

    std::vector<std::unique_ptr<Wrapper>> wrappers;

public:
    class iterator : public std::iterator<std::forward_iterator_tag, Animal*>
    {
        friend class AllAnimals;
        decltype(wrappers)::iterator current, end;
        Animal* animal;
        iterator(decltype(current) begin, decltype(end) end)
                : current(begin), end(end)//, animal(nullptr)
        {
            while(current != end && (*current)->begin() == (*current)->end())
            {
                ++current;
            }
            animal = current == end ? nullptr : (*current)->begin();
        }
    public:
        bool operator==(iterator const& other)
        {
            return current == other.current && animal == other.animal;
        }
        bool operator!=(iterator const& other)
        {
            return !(*this == other);
        }
        iterator& operator++()
        {
            if(++animal == (*current)->end())
            {
                ++current;
                animal = current == end ? nullptr : (*current)->begin();
            }
            return *this;
        }
        iterator operator++(int)
        {
            iterator i(*this);
            ++*this;
            return i;
        }
        Animal* operator*()
        {
            return animal;
        }
        Animal* operator->()
        {
            return animal;
        }
    };

    iterator begin()
    {
        return iterator(wrappers.begin(), wrappers.end());
    }
    iterator end()
    {
        return iterator(wrappers.end(), wrappers.end());
    }

    template <typename T>
    void push_back(std::vector<T*>& v)
    {
        wrappers.emplace_back(new SpecificWrapper<decltype(v)>(v));
    }
};

I only implemented a forward iterator so far, one could provide further operators to make a bidirectional or even random access one from. 到目前为止,我只实现了一个前向迭代器,可以提供进一步的操作员来进行双向甚至随机访问。 Additionally, we might add const iterators, (const) reverse iterators, ... 另外,我们可能会添加const迭代器,(const)反向迭代器,...

You may Create your Dog Vector as: 你可以创建你的狗矢量:

vector<Animal*> dogs;

And cast your dog objects before inserting them 并在插入之前投射你的狗对象

dogs.push_back((Animal*)new Dog());

Later, cast back while accessing 之后,在访问时退回

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 指向矢量的基类在派生类中 - Vector of pointers to base class within a derived class 基类的指针向量 - Vector of pointers of the base class 创建一个带有 6 个指针的向量(3 个来自基础 class,3 个来自派生类) - Creating a vector with 6 pointers(3 from base class and 3 from derived class) 有没有办法复制派生类指针的向量而不将其转换为基类? - Is there a way to copy a vector of derived class pointers without casting it to the base class? 尝试将派生类对象地址分配给基类指针的向量 - Trying to assign derived class object address to vector of base class pointers 制作基类指针的向量并将派生类对象传递给它(多态) - Making a vector of base class pointers and pass Derived class objects to it (Polymorphism) 使指向基类指针std :: vector的指针指向派生类指针的std :: vector - Making a pointer to std::vector of base class pointers point to std::vector of derived class pointers 如何在指向基类对象的指针向量中引用派生对象? - How to reference derived objects in a vector of pointers to base class objects? 是否有一种“更干净”的方法可以在指向基类的指针向量中找到派生类的第一个实例? - Is there a "cleaner" way to find the first instance of a derived class in a vector of pointers to base? 指向包含基类和派生类 class 对象的指针的向量 - 访问派生类特定变量 - Vector of pointers to base class containing base and derived class objects - accessing derived-class specific variables
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM