我想要一个派生类指针的向量作为基类指针 C++中,向量类存储对象数组。在本例中,我存储指向派生类对象(Dogs)的指针。在某种程度上,我想把这个向量当作指向基类对象(动物)的指针。这是“正确的”/无争议的方式,对吗?为什么我不能这样做 #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}; } #包括 使用名称空间std; 动物类{}; 犬类:公共动物{}; int main(int argc,char*argv[]){ 病媒狗; 狗。推回(新狗); 狗。推回(新狗); 向量动物=狗;//这似乎不起作用。 //这真的是我想做的。。。 传播所有动物[]={狗、猫、鸟}; }
错误:我想要一个派生类指针的向量作为基类指针 C++中,向量类存储对象数组。在本例中,我存储指向派生类对象(Dogs)的指针。在某种程度上,我想把这个向量当作指向基类对象(动物)的指针。这是“正确的”/无争议的方式,对吗?为什么我不能这样做 #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}; } #包括 使用名称空间std; 动物类{}; 犬类:公共动物{}; int main(int argc,char*argv[]){ 病媒狗; 狗。推回(新狗); 狗。推回(新狗); 向量动物=狗;//这似乎不起作用。 //这真的是我想做的。。。 传播所有动物[]={狗、猫、鸟}; },c++,inheritance,C++,Inheritance,错误: 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:
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)
^
Untitled.cpp:11:18:错误:从“vector”到“vector”没有可行的转换
媒介动物=狗;
^ ~~~~
/usr/include/c++/4.2.1/bits/stl_vector.h:231:7:注意:候选构造函数不可行:第一个参数没有从“vector”到“const std::vector&”的已知转换
向量(常数向量和x)
^
std::vector有一个复制构造函数,但它要求您复制完全相同类型的向量。幸运的是,还有另一个构造函数,它接受一对迭代器并添加范围内的所有元素,因此您可以这样做:
vector<Animal*> animals(dogs.begin(),dogs.end());
您可以将您的狗向量创建为:
vector<Animal*> dogs;
稍后,在访问时返回,您可以毫无问题地完成真正想做的事情!也就是说,只需做:
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();
dogs的向量
是否从动物的向量中插入?显然不是!但是所做的只是将类的名称从std::vector
更改为vectorOfDogs
接受的解决方案很好,但有一个很大的缺点:它保留了相关向量内容的副本。任何时候更新一个向量,我们都需要更新冗余数据以保持全局状态一致。由于不太喜欢,决定尝试回避这个问题(不幸的是,需要发现这需要做很多工作……):
类动物
{
结构包装器
{
虚拟~Wrapper(){}
虚拟动物*begin()=0;
虚拟动物*end()=0;
};
模板
结构特定包装器:包装器
{
T&动物;
特殊包装(T和动物)
:动物
{ }
动物*begin()覆盖
{
return*animals.begin();
}
动物*end()覆盖
{
return*animals.end();
}
};
std::向量包装器;
公众:
类迭代器:public std::iterator
{
朋友级动物;
decltype(包装器):迭代器当前,结束;
动物*动物;
迭代器(decltype(当前)开始,decltype(结束)结束)
:当前(开始)、结束(结束)/、动物(空PTR)
{
while(current!=end&&(*current)->begin()==(*current)->end())
{
++电流;
}
动物=当前==结束?空ptr:(*当前)->开始();
}
公众:
布尔运算符==(迭代器常量和其他)
{
返回current==other.current&&animal==other.animal;
}
布尔运算符!=(迭代器常量和其他)
{
返回!(*此==其他);
}
迭代器和运算符++()
{
如果(++动物==(*当前)->end())
{
++电流;
动物=当前==结束?空ptr:(*当前)->开始();
}
归还*这个;
}
迭代器运算符++(int)
{
迭代器i(*this);
++*这,;
返回i;
}
动物*操作员*()
{
返回动物;
}
动物*操作员->()
{
返回动物;
}
};
迭代器begin()
{
返回迭代器(wrappers.begin(),wrappers.end());
}
迭代器结束()
{
返回迭代器(wrappers.end(),wrappers.end());
}
模板
无效推回(标准::矢量和v)
{
包装物。将包装物放回原位(新的特殊包装物(v));
}
};
到目前为止,我只实现了一个前向迭代器,其中一个可以提供更多的操作符来进行双向甚至随机访问。此外,我们可能会添加常量迭代器,(常量)反向迭代器,…@Mahesh,因为你永远都不想做
无效oops(向量和动物){动物。推回(新猫)}向量狗;oops(狗)
。不过,这种解决方案有一个缺点:所有动物
维护其他载体内容的副本,因此如果更新其中一个,所有动物都不会自动更新…@molbdnilo这是什么样的参数?它与void oops(动物和动物){Animal=*新猫;}狗*狗有什么不同;oops(*狗)代码>?
dogs.push_back((Animal*)new Dog());
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();
class vectorOfDogs {
Dog* myDogs;
//...
}
class vectorOfAnimals {
Animal* myAnimals;
//...
}
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));
}
};