C++ 访问存储在向量C+中的结构的多态成员+;
我有一个结构a和结构B(B继承自a)。有没有一种方法可以创建std::vector,它的模板类型为a,但可以接受B类型的结构,当遍历时,我可以访问结构B专有的成员(显然是检查以确保它是B类型的)。您可以使用存储对象作为指针,并使用C++ 访问存储在向量C+中的结构的多态成员+;,c++,polymorphism,C++,Polymorphism,我有一个结构a和结构B(B继承自a)。有没有一种方法可以创建std::vector,它的模板类型为a,但可以接受B类型的结构,当遍历时,我可以访问结构B专有的成员(显然是检查以确保它是B类型的)。您可以使用存储对象作为指针,并使用动态\u cast检查向下转换 #include <iostream> #include <memory> #include <vector> struct A { virtual ~A() = default; }; stru
动态\u cast
检查向下转换
#include <iostream>
#include <memory>
#include <vector>
struct A {
virtual ~A() = default;
};
struct B : public A {
void test() { std::cout << "I'm B(" << this << ")" << std::endl; }
};
int main() {
std::vector<std::unique_ptr<A>> elements;
elements.push_back(std::make_unique<A>());
elements.push_back(std::make_unique<B>());
for (const auto &e : elements) {
if (auto ptr = dynamic_cast<B *>(e.get())) {
ptr->test();
}
}
return 0;
}
#包括
#包括
#包括
结构A{
virtual~A()=默认值;
};
结构B:公共A{
void test(){std::cout您可以使用存储对象作为指针,并使用dynamic_cast
检查向下转换
#include <iostream>
#include <memory>
#include <vector>
struct A {
virtual ~A() = default;
};
struct B : public A {
void test() { std::cout << "I'm B(" << this << ")" << std::endl; }
};
int main() {
std::vector<std::unique_ptr<A>> elements;
elements.push_back(std::make_unique<A>());
elements.push_back(std::make_unique<B>());
for (const auto &e : elements) {
if (auto ptr = dynamic_cast<B *>(e.get())) {
ptr->test();
}
}
return 0;
}
#包括
#包括
#包括
结构A{
virtual~A()=默认值;
};
结构B:公共A{
void test(){std::coutTarek的答案适用于使用动态内存分配(如果sizeof(B)
明显大于sizeof(A)
,通常会更好)的常见情况。我不想与这个答案竞争,只是增加一些讨论点。在很多情况下(但远不是所有情况下)问题域将dynamic_u u cast
而不是添加到a
avirtualvoid test(){}
-注意函数体什么都不做-然后使B
的test
重写(即void test()重写{…现有体…}
)。这样,循环可以只说ptr->test()
,而不关心运行时类型(即它是否实际上是B
对象)。如果“test
”操作对于类的整个继承权有某种逻辑意义,但是现在在A
中没有什么值得测试的,特别是当您直接或通过B
添加从A
派生的C
类型时,它还需要从循环调用test
函数:您真的不需要您需要转到每个这样的循环并添加额外的dynamic\u cast
测试
只是为了好玩,有一个替代方案恰好更接近您对向量
的请求,它可以“接受B
类型结构”(尽管不再是向量
),您可以使用std::variant
获得大致相同的结果,并将A
或B
直接存储在矢量管理的连续内存中,如果大小差异很小或内存使用情况无关紧要,则效果最佳,但对象足够小,因此CPU缓存位置对其非常有用表演
#include <vector>
#include <iostream>
#include <variant>
struct A {
virtual void f() const { /* do nothing */ }
};
struct B : A {
int i_;
B(int i) : i_{i} { }
void f() const override { std::cout << "B\n"; }
void g() const { std::cout << "B::g() " << i_ << '\n'; }
};
int main()
{
std::vector<std::variant<A, B>> v{ A{}, A{}, B{2}, A{}, B{7}, B{-4}, A{} };
for (const auto& x : v)
if (const auto* p = std::get_if<B>(&x))
p->g();
}
#包括
#包括
#包括
结构A{
虚空f()常量{/*不执行任何操作*/}
};
结构B:A{
国际组织;
B(inti):i{i}{}
void f()const override{std::cout sizeof(A)
,placementnew
-将B
对象插入向量
将覆盖以下对象的内存(或关闭向量
)
我听说有一个东西叫做Copeland虚拟构造函数习惯用法,其中对象的类型更改类似于操作符new(&a)B{}
(尽管在这种情况下,它可以从构造函数操作符new(this)B{}
完成),但您必须是语言和/或实现专家才能知道它是否/何时使用是安全的。Tarek的答案适用于使用动态内存分配的常见情况(如果sizeof(B)
明显大于sizeof(a)
,则通常更好)。我不想与这个答案竞争,只是增加一些讨论点。在许多(但远不是所有)问题领域,将dynamic\u cast
,而不是添加到a
avirtual void test(){}被认为是一种糟糕的做法
-注意函数体什么都不做-然后使B
的test
成为一个覆盖(即void test()覆盖{…现有体…}
)。这样,循环就可以说ptr->test()
,而不关心运行时类型(即它是否实际上是B
对象)。如果“测试”
,则此方法更有意义操作对于类的整个继承权有某种逻辑意义,但是现在在A
中没有什么值得测试的,特别是当您直接或通过B
添加从A
派生的C
类型时,它还需要从循环调用test
函数:您真的不需要您需要转到每个这样的循环并添加额外的dynamic\u cast
测试
只是为了好玩,有一个替代方案恰好更接近您对向量
的请求,它可以“接受B
类型结构”(尽管不再是向量
),您可以使用std::variant
获得大致相同的结果,并将A
或B
直接存储在矢量管理的连续内存中,如果大小差异很小或内存使用情况无关紧要,则效果最佳,但对象足够小,因此CPU缓存位置对其非常有用表演
#include <vector>
#include <iostream>
#include <variant>
struct A {
virtual void f() const { /* do nothing */ }
};
struct B : A {
int i_;
B(int i) : i_{i} { }
void f() const override { std::cout << "B\n"; }
void g() const { std::cout << "B::g() " << i_ << '\n'; }
};
int main()
{
std::vector<std::variant<A, B>> v{ A{}, A{}, B{2}, A{}, B{7}, B{-4}, A{} };
for (const auto& x : v)
if (const auto* p = std::get_if<B>(&x))
p->g();
}
#包括
#包括
#包括
结构A{
虚空f()常量{/*不执行任何操作*/}
};
结构B:A{
国际组织;
B(inti):i{i}{}
void f()const override{std::cout sizeof(A)
,placementnew
-将B
对象插入向量
将覆盖以下对象的内存(或关闭向量
)
我听说有一个东西叫做Copeland虚拟构造函数习惯用法,其中对象的类型更改类似于操作符new(&a)B{}
(尽管在这种情况下,它可以从构造函数操作符new(this)B{}
完成),但您必须是语言和/或实现专家,才能知道它是否/何时可以安全使用。是的,这是可能的