gpt4 book ai didi

c++ - 如何在基类指针 vector 的元素上应用重载的多态函数

转载 作者:行者123 更新时间:2023-12-02 09:50:27 32 4
gpt4 key购买 nike

我有一个基类Object:

struct Object{
};

n(在这种情况下为2)从该类继承的类
struct Integer : public Object{
int i_;
Integer(int i) : i_{i}{}
}

struct Float : public Object{
float f_;
Float(float f) : f_{f}{}
}

通过使用多态性,我现在可以将这两种类型存储在 vector 中:
std::vector<Object*> object_list{new Integer(1), new Float(2.1), new Integer(3), new Float(4.2)};

但是现在我想将所有这些值加在一起。

我能想到...

1)...定义功能
Integer* add(Integer* i, Integer* j);
Float* add(Integer* i, Float* f);
Float* add(Float* f, Float* g);
Float* add(Float* f, Integer* i);

但这需要将 Object动态转换为所有可用类型-两次,如果我有足够的子类,这似乎是一场灾难。

2)...模板,但是不起作用,因为类型在编译时未知。

那么关于以下要求的最有效方法是:

*执行时间比内存使用更为重要(尽管它应该在8GB系统上运行)

*它应支持任意数量的子类,但至少必须达到20个

*不限于添加,而是应支持任意函数 f(Object* a, Object* b)
*类(class)的设计尚未确定。如果某项工作需要更改(或更改自身的总体结构),则可能

*所有可能的类型都是预先已知的,不需要支持外部DLL

*不需要支持多重继承

*不需要在错误处理方面强大。可恢复会很好,但我可以忍受SEGFAULT。

最佳答案

using Object = std::variant<Float, Integer>;

现在,您可以拥有一个 std::vector<Object>并在其中存储 FloatInteger
struct Integer {
int val = 0;
friend std::ostream& operator<<( std::ostream& os, Integer const& obj ) {
return os << obj.val;
}
};
struct Float {
double val = 0.;
friend std::ostream& operator<<( std::ostream& os, Float const& obj ) {
return os << obj.val;
}
};

using Object = std::variant<Integer, Float>;
std::ostream& operator<<( std::ostream& os, Object const& obj ) {
// note: if the type in Object doesn't have a << overload,
// this will recurse and segfault.
std::visit( [&]( auto const& e ){ os << e; }, obj );
return os;
}

Integer add_impl(Integer const& i, Integer const& j) { return {i.val + j.val}; }
Float add_impl(Integer const& i, Float const& j) { return {i.val + j.val}; }
Float add_impl(Float const& i, Float const& j) { return {i.val + j.val}; }
Float add_impl(Float const& i, Integer const& j) { return {i.val + j.val}; }

Object add( Object const& lhs, Object const& rhs ) {
return std::visit( []( auto& lhs, auto& rhs )->Object { return {add_impl( lhs, rhs )}; }, lhs, rhs );
}

Test code:
Object a = Integer{7};
Object b = Float{3.14};
Object c = Integer{-100};
Object d = Float{0.0};

std::cout << add( a, b ) << "," << add( b, c ) << "," << add( c, d ) << "," << add( add(a, b), add( c, d ) ) << "\n";

这实现了一个调度表(较新的编译器将生成效率更高的调度表),该表将查找 add重载。

返回类型是 Object,但在运行时将包含 FloatInteger

您需要支持的类型列表必须位于 Object的定义处。这些对象不必是相关类型。

您可以在 add_impl中的类型的 namespace 中而不是在中心位置扩展 Object。 ADL将用于查找过载集。

当然是 I'd implement operator+ instead of add

您可以使用一些技巧来修复:
// note: if the type in Object doesn't have a << overload,
// this will recurse and segfault.

这个问题;基本上是这样的:
namespace ObjectOnly {
struct Object;
struct Object:std::variant<Integer, Float> {
using std::variant<Integer, Float>::variant;
std::variant<Integer, Float> const& base() const& { return *this; }
std::variant<Integer, Float> & base()& { return *this; }
std::variant<Integer, Float> const&& base() const&& { return std::move(*this); }
std::variant<Integer, Float> && base()&& { return std::move(*this); }
};
Object add_impl( Object const& lhs, Object const& rhs ) {
return std::visit( [](auto& lhs, auto& rhs)->Object { return {lhs+rhs}; }, lhs.base(), rhs.base() );
}
Object operator+( Object const& lhs, Object const& rhs ) {
return add_impl( lhs, rhs );
}
std::ostream& stream_impl( std::ostream& os, Object const& obj ) {
std::visit( [&]( auto const& e ){ os << e; }, obj.base() );
return os;
}
std::ostream& operator<<( std::ostream& os, Object const& obj ) {
return stream_impl( os, obj );
}
}

这将阻止 add_impl看到 ObjectOnly::operator+。仍然可以在与 operator+Float相同的命名空间中看到 Integer

参见 here。如果您将 Integer编辑为不支持 <<,则会得到编译时错误,而不是运行时错误。

关于c++ - 如何在基类指针 vector 的元素上应用重载的多态函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60060462/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com