继承类类型的c++容器
c++ container of inherited class types
我想要一个容器(比如std::vector),它可以容纳各种继承的类型,并实例化它们,即类的向量-->对象的向量。
例如:
class A{};
class B: public class A
{};
class C: public class A
{};
void main()
{
std::vector<of inherited A types> typesVec;
std::vector<A*> objectsVec;
typesVec.push_back(class B);
typesVec.push_back(class C);
for (int i = 0; i < typesVec.size(); i++)
{
A* pA = new typesVec.at(i);
objectsVec.push_back(pA);
}
}
提前谢谢。。
这在C++中是不可能的(至少不能直接实现)。我可以在一种有反射的语言中看到这种情况,但C++没有。
相反,您可以创建一个工厂,或者简单地创建指定类型的对象的方法。
与其有一个类型向量,不如有一个对象生成器向量(足够接近,对吧?):
class A{};
class B: public class A
{};
class C: public class A
{};
struct AFactory
{
virtual A* create() { return new A; }
};
struct BFactory : AFactory
{
virtual A* create() { return new B; }
};
struct CFactory : AFactory
{
virtual A* create() { return new C; }
};
//...
typesVec.push_back(new BFactory);
typesVec.push_back(new CFactory);
for (int i = 0; i < typesVec.size(); i++)
{
A* pA = typesVec.at(i)->create();
objectsVec.push_back(pA);
}
有一种可重用的模板方法。这是派生类型的通用工厂,带有install
和create
方法,可以编写如下代码:
int main() {
TypeVector<Base> t;
t.install<Foo>("Foo");
t.install<Bar>("Bar");
t.create("Foo")->hello();
}
请注意,这是一个草图实现。在现实世界中,您可以提供另一个模板参数来指定底层容器类型(对于少数类型,vector
可能比set
更有效)。
类型矢量是这样的:
template <typename Base>
class Creator;
template <typename Base>
class TypeVector {
public:
template <typename Derived>
void install (std::string const &name) ;
std::shared_ptr<Base> create (std::string const &name) const;
private:
struct Meta {
Meta(std::shared_ptr<Creator<Base>> creator, std::string const &name)
: creator(creator), name(name) {}
std::shared_ptr<Creator<Base>> creator;
std::string name;
};
std::vector<Meta> creators_;
};
我们需要一种以可分配的方式存储类型的方法。我们这样做就像boost::shared_ptr
,它结合了一个抽象基类和一个模板派生类:
template <typename Base>
class Creator {
public:
virtual ~Creator() {}
virtual std::shared_ptr<Base> create() const = 0;
};
template <typename Base, typename Derived>
class ConcreteCreator : public Creator<Base> {
public:
virtual std::shared_ptr<Base> create() const {
return std::shared_ptr<Base>{new Derived()};
}
};
"具体创建者"能够分配一个实际的对象,并返回一个指向其基础的指针
最后,这里是TypeVector::install
和TypeVector::create
:的实现
template <typename Base>
template <typename Derived>
void
TypeVector<Base>::install (std::string const &name)
{
creators_.emplace_back(
std::shared_ptr<Creator<Base>>(new ConcreteCreator<Base, Derived>()),
name);
}
template <typename Base>
std::shared_ptr<Base>
TypeVector<Base>::create (std::string const &name) const
{
for (auto m : creators_) {
if (name == m.name) return m.creator->create();
}
throw std::runtime_error("...");
}
最后,这里有一个测试:
#include <iostream>
struct Base {
virtual ~Base() {}
virtual void hello() const = 0;
};
struct Foo : Base {
virtual void hello() const { std::cout << "I am a Foon"; }
};
struct Bar : Base {
virtual void hello() const { std::cout << "I am a Barn"; }
};
int main() {
TypeVector<Base> t;
t.install<Foo>("Foo");
t.install<Bar>("Bar");
t.create("Foo")->hello();
}
您可以更进一步,使任何构造函数都可以为以下代码调用。。。
...
Bar(Color, Age, int)
...
t.create("Foo", Color::Red, Age::TooOld, 42)
但这需要对可变模板参数列表有一个极好的理解,以及如何将它们折叠到构造函数调用中(可以完成,也已经完成,但它会爆炸这个答案)。
只是一个快速解决方案草图:
C++标准不提供对构造函数的直接调用。因此,不能有指向构造函数的函数指针;但是,您可以有一个包装器函数"create",类似于:
template<typename T>
T* create () {
return (new T();
}
为一个参数、两个参数等提供重载的创建定义。。。或者尝试使用可变模板;或者,如果您已经知道需要什么类型,可以专门创建create函数。然后你可以有一个指向创建函数的函数指针:
&create<TheType>
请注意,此函数的签名取决于所使用的类型。但是,您可以创建一个结构,该结构包含模板化类型的typedef、类型指针的typedef,以及作为函数operator()
的create函数。
因此,您可以有两个向量,一个用于创建函数的函数指针,或者用于前面提到的结构,另一个用于实际对象。在您只有继承类型的情况下,您可以定义函数A* createB() { return new B(); }
、A* createC() { return new C(); }
。。。对于每个继承的类型B、C。。。并且具有用于指向这些创建函数的指针的矢量和用于a指针的第二矢量。
我可以为您介绍Andrei Alesandrescu的《现代C++设计》一书(或他在书中描述的Loki库)和关于类型列表的章节。这将要求您在编译时执行typeVec.insert( type )
。
- 在提升multi_index容器中,是否定义了"default index"?
- 用于访问容器<T>数据成员的正确 API
- Eigen如何在容器循环中干净地附加矩阵
- 模板专用化(按容器):value_type
- 关联容器的下界复杂性:成员函数与非成员函数
- 更多constexpr容器是否需要mark_immutable_if_consexpr
- 在STL容器中使用模板类
- 当有分配器意识的容器被复制/移动时,反弹分配器是否被复制/移走
- 检查函数返回类型是否与STL容器类型值相同
- STL算法函数在多个一维容器上的使用
- 如何将带有自定义对象的容器从C++传递到QML
- 在没有未定义行为的情况下实现类似std::vector的容器
- 将 BASE 派生类存储在同一容器中
- 为什么 STL 容器适配器堆栈中的 top 返回常量引用?
- 在C++中迭代 2D 容器的最干净方法
- 将线程中的数据存储到全局容器的最佳方法?
- 如果我真的真的想从 STL 容器继承,并且我继承构造函数并删除新运算符,会发生什么?
- 使用带有C++对象和标准库容器的插件系统
- 使用 std::index_sequence 初始化具有固定大小数组成员的 POD 结构容器
- 我可以用字符串变量而不是它的名字创建容器吗? C++