有没有办法
container< container<Base> >当您有一堆希望保持在一起的container<Derived>(迭代器?)
下面是一个具体的例子。
说你有
struct Animal { } ;
struct Dog : public Animal { } ;
struct StripedDog : public Dog { } ;
struct Cat : public Animal { } ;
struct SpottedCat : public Cat { } ;您希望将猫、SpottedCats、Dogs和StripedDogs的集合保存在向量或列表中,
vector<Dog*> doggies ;
vector<StripedDog*> stripedDoggies ;
vector<Cat*> catties ;
vector<SpottedCat*> spottedCatties ;但是,您希望遍历所有的动物,因此您希望将对所有狗和猫集合的引用转换为一个对象,
vector< vector<Animal *>* > zoo ;
zoo.push_back( &doggies ) ;
zoo.push_back( &stripedDoggies ) ;
zoo.push_back( &catties ) ;
zoo.push_back( &spottedCatties ) ;所以现在你可以
feed( zoo ) ;当然,这不能编译。猫和狗的媒介不是vector<Animal*>,而是它们具体类型的载体。在不保留冗余列表和不丢失具体类型信息的情况下(即不像在vector<Animal*> stripedDoggies中那样使用基类型Animal*列表),是否有一种方法可以实现C++的等效行为?
发布于 2013-10-10 00:24:11
我想你是在看这样的东西,但不太确定。如果它不接近你所需要的,请告诉我,我会放弃它,以求帮助那些需要的人。输出演示虚拟feed()操作适当地执行其业务。为该函数安排一个潜在的变量参数包将花费我一段时间来烹饪,我甚至不确定这是否可能。
但这应该能让你接近。
#include <iostream>
#include <algorithm>
#include <type_traits>
#include <vector>
// base. enforces inheritance by SFINAE
template<typename Base, typename T, template<typename, typename...> class V>
typename std::enable_if<std::is_base_of<Base, T>::value>::type
invoke(void (Base::*func)(), const class V<T*>& vec)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
for (auto p : vec)
(p->*func)();
}
// chain.
template<typename Base, typename T, template<typename, typename...> class V, typename... Args>
typename std::enable_if<std::is_base_of<Base, T>::value>::type
invoke(void (Base::*func)(), const class V<T*>& vec, Args... args)
{
invoke(func, vec);
invoke(func, args...);
}
int main()
{
struct Animal
{
virtual void feed()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
} ;
struct Dog : public Animal
{
void feed()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
} ;
struct StripedDog : public Dog {};
struct Cat : public Animal {};
struct SpottedCat : public Cat {};
std::vector<Dog*> doggies ;
std::vector<StripedDog*> stripedDoggies ;
std::vector<Cat*> catties ;
std::vector<SpottedCat*> spottedCatties ;
Dog dog;
doggies.push_back(&dog);
StripedDog sdog;
stripedDoggies.push_back(&sdog);
Cat cat;
catties.push_back(&cat);
invoke(&Animal::feed, doggies, stripedDoggies, catties, spottedCatties);
return 0;
}输出
typename std::enable_if<std::is_base_of<Base, T>::value>::type invoke(void (Base::*)(), const class V<T *> &) [Base = Animal, T = Dog, V = vector]
virtual void main()::Dog::feed()
typename std::enable_if<std::is_base_of<Base, T>::value>::type invoke(void (Base::*)(), const class V<T *> &) [Base = Animal, T = StripedDog, V = vector]
virtual void main()::Dog::feed()
typename std::enable_if<std::is_base_of<Base, T>::value>::type invoke(void (Base::*)(), const class V<T *> &) [Base = Animal, T = Cat, V = vector]
virtual void main()::Animal::feed()
typename std::enable_if<std::is_base_of<Base, T>::value>::type invoke(void (Base::*)(), const class V<T *> &) [Base = Animal, T = SpottedCat, V = vector]很抱歉,必须向右滚动才能看到漂亮打印中的类型,但是它们很有说服力,应该看一下它是如何工作的。请注意,Dog和StripedDog容器都正确地触发了Dog::feed()成员,而Cat容器正确地触发了Animal::feed()基本成员,因为它不提供任何覆盖。
祝你好运,我希望这能帮上忙。
发布于 2013-10-09 23:47:58
通常,如果您正在执行这样的操作,您将将它们全部存储在一个向量中:
std::vector<std::shared_ptr<Animal>> animals;如果Animal定义了一个feed方法,那么迭代它就意味着调用该函数:
animals[i]->feed();如果要根据类型调用特定函数,则需要执行一些强制转换:
std::shared_ptr<Dog> pDog = std::dynamic_pointer_cast<Dog>(animals[i]);
std::shared_ptr<Cat> pCat = std::dynamic_pointer_cast<Cat>(animals[i]);
// other casts
if (pDog)
{
// do something with a dog
}
else if (pCat)
{
// do something with a cat
}
// etc如果您真的想将所有的animals存储在附加的vector中,可以通过包装整个动物园来实现:
class Zoo
{
private:
std::vector<std::shared_ptr<Animal>> animals;
std::vector<std::shared_ptr<Dog>> dogs;
// other vectors
public:
void AddDog(const Dog& d)
{
std::shared_ptr<Dog> pD = std::make_shared<Dog>(d);
dogs.push_back(pD);
std::shared_ptr<Animal> pA = std::static_pointer_cast<Animal>(pD);
animals.push_back(pA);
}
};它是存储在内存中的指针数量的两倍,但是指针相当便宜。然后你可以通过整个动物园,或个别动物类型,而不需要做每一次的铸造。
发布于 2013-10-09 23:54:22
由于您使用的是相当便宜的指针,所以您可能会这样做:
vector< Animal * > zoo;
zoo.append( zoo.end(), doggies.begin(), doggies.end() );
// ditto with the others
feed( zoo ); // just receives *one* vector with animals to feed如果不想复制/合并向量,另一个选项是:
void feed() {}
template< typename V >
void feed( const V& v )
{
for( A* a : v )
{
// ...do something with 'a'
}
}
template< typename V, typename V2, typename... Vs >
void feed( const V& v, const V2& v2, const Vs&... vs )
{
feed( v );
feed( v2, vs... );
}现在你可以打电话给feed( doggies, stripedDoggies, catties, spottedCatties );了。
https://stackoverflow.com/questions/19284660
复制相似问题