有没有可能在 * 任何 * std c++容器中保持派生类的知识而不使用指针,动态地从容器中转换返回值?我知道我可以创建一个向量,比如说,一些基类类型的指针,并让它们保留它们的子类。但问题是我必须使用指针吗?
示例:
struct A {
int x = 0, y = 0, z = 0;
virtual void foo() { cout << "A" << endl; };
};
struct B : public A {
int a = 1, b = 1, c = 1;
virtual void foo() { cout << "B" << endl; };
};
int main() {
<SOMECONTAINER><A> a(2);
a[0] = A();
a[1] = B();
B * p;
B& n = dynamic_cast<B&>(a[1]); // Always throws?
p = dynamic_cast<B*>(&a[1]); // Always zero?
cout << p << endl;
}
5条答案
按热度按时间nfzehxib1#
是的,你必须使用指针,否则,试图把一个
B
放入A
的容器中会导致slicing:B
被削减为A
(这不限于容器,如果您执行A a = B()
或将B
传递给期望A
的函数,则会发生完全相同的情况)。当你后来把它拿出来时,它是一个
A
,完全不知道它的血统包括B
类型的杰出祖先--不管你怎么看A
,你都不能把它变成B
。ctzwtxfj2#
我将忽略对齐,或者更确切地说,假设指针后面的数据充分对齐。
这是我对多态变体的尝试,它存储
T
和T
的孩子,只要他们不大于N
,并且可以存储在std
容器中。编译好了告诉我。
rfbsl7qr3#
你需要指针用于虚成员函数调度。
当你考虑它的时候,如果没有指针,你就只能“按值”了,值语义和多态性在一起并没有什么意义。
一个 value 只有一个上下文/类型。它是原子的,简单的。可以说是所见即所得。当然,你可以强制转换它,但是那样你就有了...另一个值。
u1ehiz5o4#
有一句经常被引用的程序员谚语:除了太多的间接层之外,没有任何问题不能用附加的间接层来解决。
将其付诸实践,请看
boost::variant
。如果你的容器存储了
boost::variant
,允许所有你想要存储的(子)类,你可以避免指针。这可能是一场胜利,但也不一定是。
在你承诺这样一个解决方案之前进行衡量。
ldioqlga5#
我认为这里实际上有两个问题:
1.有没有可能在STL容器中获得多态语义而不使用指针和相关的动态分配?
1.有没有可能保留存储在STL容器中的多态对象的具体类型?
1的答案是肯定的,但要付出一些努力。正如一些人提到的,一种方法是使用boost::variant这样的变体类型。这种方法的问题是,您失去了与存储在变体中的对象自然交互的能力,而是必须编写访问者,这会产生大量的语法开销。
如果类的层次结构是有界的,那么一个更好的方法可能是使用boost::variant的一个变体(没有双关语),这个变体是专门设计来保留多态语义和相关语法的,emplacer就是一个例子,正如dyp上面的注解所指出的,emplacer是一个受限的变体。
至于问题2,我不知道有没有不使用typeid()或手动滚动类型系统的方法。