C++ 我可以播放std::vector<;动物*>;到std::vector<;狗*>;不看每个元素?
我有一个基类,有几个类扩展它。我有一些通用的库实用程序,它创建一个向量,其中包含指向基类的指针,这样任何子类都可以工作。如何将向量的所有元素强制转换为特定的子类C++ 我可以播放std::vector<;动物*>;到std::vector<;狗*>;不看每个元素?,c++,templates,vector,casting,C++,Templates,Vector,Casting,我有一个基类,有几个类扩展它。我有一些通用的库实用程序,它创建一个向量,其中包含指向基类的指针,这样任何子类都可以工作。如何将向量的所有元素强制转换为特定的子类 // A method is called that assumes that a vector containing // Dogs casted to Animal is passed. void myDogCallback(vector<Animal*> &animals) { // I want to
// A method is called that assumes that a vector containing
// Dogs casted to Animal is passed.
void myDogCallback(vector<Animal*> &animals) {
// I want to cast all of the elements of animals to
// be dogs.
vector<Dog*> dogs = castAsDogs(animals);
}
//调用一个方法,该方法假定包含
//被铸造成动物的狗被传了。
无效myDogCallback(病媒和动物){
//我想把动物的所有元素都投射到
//做狗。
病媒狗=卡斯塔斯狗(动物);
}
我的天真解决方案如下所示:
// A method is called that assumes that a vector containing
// Dogs casted to Animal is passed.
void myDogCallback(vector<Animal*> &animals) {
// I want to cast all of the elements of animals to
// be dogs.
vector<Dog*> dogs;
vector<Animal*>::iterator iter;
for ( iter = animals.begin(); iter != animals.end(); ++iter ) {
dogs.push_back(dynamic_cast<Dog*>(*iter));
}
}
//调用一个方法,该方法假定包含
//被铸造成动物的狗被传了。
无效myDogCallback(病媒和动物){
//我想把动物的所有元素都投射到
//做狗。
病媒狗;
向量:迭代器iter;
for(iter=animals.begin();iter!=animals.end();++iter){
狗。推回(动态投射(*iter));
}
}
当动物向量包含其他动物特化时,您编写的代码将向dogs向量中放入一堆空指针
vector<Dog*> dogs;
vector<Animal*>::iterator iter;
Dog* dog;
for( iter = animals.begin(); iter != animals.end(); ++iter )
{
dog = dynamic_cast<Dog*>(*iter);
if( dog )
{
dogs.push_back( dog );
}
}
矢量狗;
向量:迭代器iter;
狗*狗;
for(iter=animals.begin();iter!=animals.end();++iter)
{
dog=动态熔铸(*iter);
如果(狗)
{
狗。推回(狗);
}
}
通常,使用动态投影进行向下投影不是很好。您可能应该重构代码,这样就不需要使用显式向下转换
有关更多信息,请参阅
UPD另请参见(搜索“为什么我不能将向量指定给向量?”)您可以使用
std::transform
。它仍然在内部使用for()
,但您将得到两个字符串实现:
#include <vector>
#include <algorithm>
using namespace std;
struct Animal { virtual ~Animal() {} };
struct Dog : Animal { virtual ~Dog() {} };
template<typename Target>
struct Animal2Target { Target* operator ()( Animal* value ) const { return dynamic_cast<Target*>(value); } };
void myDogCallback(vector<Animal*> &animals) {
{
vector<Dog*> dogs;
transform( animals.begin(), animals.end(), dogs.begin(), Animal2Target<Dog>() );
}
#包括
#包括
使用名称空间std;
结构动物{virtual~Animal(){};
结构狗:动物{virtual~Dog(){};
模板
struct Animal2Target{Target*操作符()(动物*值)const{return dynamic_cast(值);};
无效myDogCallback(病媒和动物){
{
病媒狗;
转换(animals.begin()、animals.end()、dogs.begin()、Animal2Target());
}
有两种选择。最简单的方法是在的情况下使用remove\u copy\u之类的方法。我无法解释为什么他们会这样称呼它,但它会将不满足谓词的元素从一个容器复制到另一个容器。以下是基本思想(未测试):
这很粗糙,但我希望它能向你展示基本原理。如果你说你能保证每个元素都是真正的狗,那么只需静态施法即可
void myDogCallback(vector<Animal*> &animals) {
const vector<Animal*>::size_type numAnimals = animals.size();
vector<Dog*> dogs;
dogs.reserve( numAnimals );
for ( vector<Animal*>::size_type i = 0; i < numAnimals; ++i ) {
dogs.push_back(static_cast<Dog*>( animals[i] ));
}
}
void myDogCallback(向量和动物){
常量向量::size_type numAnimals=anives.size();
病媒狗;
狗。保护区(纽曼马尔);
对于(向量::大小\类型i=0;i
我通常会从人们那里得到下意识的反应,这是不好的,你应该总是使用dynamic\u cast
,但是,实际上,如果你能对类型做出保证,那么它是完全安全的,我认为这是一件明智的事
此外,您的保证意味着新向量具有相同的大小,因此保留相同的空间,以避免在每个推回
中进行任何分配。作为替代循环,我使用了索引,只是因为我始终认为使用索引进行迭代必须比迭代器更快,但这可能是胡说八道:)如果您可以保证,如果你的std::vector
只包含Dog*
,你可以使用reinterpret\u cast将std::transform
方法与static\u cast
混合使用(因为你确信它的安全性),可以如下所示:
std::transform(animals.begin(), animals.end(),
std::back_insert_iterator<std::vector<Dog*>>(dogs),
[](auto ptr) { return static_cast<Dog*>(ptr); });
std::transform(anists.begin(),anists.end(),
标准::返回插入迭代器(狗),
[](自动ptr){return static_cast(ptr);};
复制:这不是完全重复-注意,他不是从向量
复制到向量
,而是从另一个角度复制!我猜他在寻找一种自动/隐含的沮丧!感谢反馈。:)不确定如何问这个问题,是的,很难知道要搜索什么!这仍然是“查看每个元素”,则流的排列方式不同。违反严格的别名:
void myDogCallback(vector<Animal*> &animals) {
const vector<Animal*>::size_type numAnimals = animals.size();
vector<Dog*> dogs;
dogs.reserve( numAnimals );
for ( vector<Animal*>::size_type i = 0; i < numAnimals; ++i ) {
dogs.push_back(static_cast<Dog*>( animals[i] ));
}
}
std::transform(animals.begin(), animals.end(),
std::back_insert_iterator<std::vector<Dog*>>(dogs),
[](auto ptr) { return static_cast<Dog*>(ptr); });