编辑:这方面的一个更好的标题是:不需要单独的堆分配的大型对象集合的多态性。
假设我有一个带有虚拟函数的基类Animal
和一些派生类(Cat
、Dog
等)。实际的派生类包含4-8字节的数据.我想要存储一个std::list<Animal>
,它实际上包含派生对象的项。我希望避免使用new在堆中创建许多小对象。
有什么设计模式可以用来实现这一点吗?
编辑:我的想法来实现这一点
std::deque<Cat>
,std::deque<Dog>
,.;存储包含来自deques
的指针的std::list<Animal*>
;我使用std::deque
是因为我认为它对大块对象具有良好的内存管理;发布于 2015-02-20 11:42:11
我意识到这个问题很老,但我找到了一个有点不错的解决办法。
假设:
您预先知道所有的派生类(给定您的编辑,这是正确的)。
技巧:
使用boost::variant (0/doc/html/variant.html)
示例类:
class Animal {
public:
virtual void eat() = 0;
};
class Cat : public Animal {
virtual void eat() final override {
std::cout << "Mmh, tasty fish!" << std::endl;
}
};
class Dog: public Animal {
virtual void eat() final override {
std::cout << "Mmh, tasty bone!" << std::endl;
}
};
示例变体/访问者:
typedef boost::variant<Cat, Dog> AnimalVariant;
class AnimalVisitor : public boost::static_visitor<Animal&> {
public:
Animal& operator()(Cat& a) const {
return a;
}
Animal& operator()(Dog& a) const {
return a;
}
};
示例用法:
std::vector<AnimalVariant> list;
list.push_back(Dog());
list.emplace_back(Cat());
for(int i = 0; i < 5; i++) {
for(auto& v : list) {
Animal& a = v.apply_visitor(AnimalVisitor());
a.eat();
}
}
示例输出
Mmh, tasty bone!
Mmh, tasty fish!
Mmh, tasty bone!
Mmh, tasty fish!
Mmh, tasty bone!
Mmh, tasty fish!
Mmh, tasty bone!
Mmh, tasty fish!
Mmh, tasty bone!
Mmh, tasty fish!
发布于 2011-08-28 21:32:16
对于包含每个案例所需的超级数据集的联合,您可能可以使用一个简单的包装类来完成一些操作。这将包含一个指向共享策略对象的指针,该对象包含不同行为的代码。所以cat是PolyAnimal类的对象,speciesName = "cat",PredatorFeedingStrategy等等。
解决潜在问题的一个更好的方法可能是为更自然的设计设置适当的自定义分配器。
发布于 2022-10-28 15:19:20
如果所有可能的子类都是在编译时已知的(这种情况也称为“封闭集多态”),这是对使用变体(无论是Boost的还是自cxx17以来的STL )的建议的后续跟进。
必须使用访问者模式访问对象的接口有点烦人(imo),这就是为什么我编写了一个公开基类接口(甚至基类操作符)的变体类型。它可以在变体中找到(需要C++17,因为它是围绕std::variant
构建的)。
从@Draziv克隆示例:
类-定义
class Animal {
public:
virtual void eat() = 0;
};
class Cat : public Animal {
virtual void eat() final override {
std::cout << "Mmh, tasty fish!" << std::endl;
}
};
class Dog: public Animal {
virtual void eat() final override {
std::cout << "Mmh, tasty bone!" << std::endl;
}
};
示例用法
pv::polymorphic_variant< Animal, Dog, Cat > variant;
variant->eat();
variant = Cat{};
variant->eat();
输出:
Mmh, tasty bone!
Mmh, tasty fish!
https://stackoverflow.com/questions/7223613
复制相似问题