[英]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.