为什么C++中不能声明 std::vector<AbstractClass>?2025年2月11日 | 阅读 7 分钟 概述C++底层标准模板库(STL)的几个主要组成部分之一是动态集合 std::vector,它可以容纳几乎任何类型的结构。它随后提供了一种易于修改且成功的方法来管理各种资源。std::vector 和抽象类(std::vector)的结合经常在开发者之间引起困惑。因此,有必要检查抽象类的特性及其与 STL 容器和 C++ 类型系统的交互,以理解为什么这种策略会产生问题。 在编程语言中,C++ 中的抽象方法,特别是任何拥有至少一个纯虚函数的类,即无法直接使用或实现的函数。通过为其他类提供基础,抽象类通过派生类促进了定制。 ![]() std::vector 无法直接处理它们,因为抽象类不能被实例化,这导致了一个根本性的不一致。 为了解决这个限制,开发者在与 std::vector 配合使用抽象类类型时,通常会使用指针或智能指针。通过在 vector 中存储指向派生类的指针,而不是抽象基类本身,他们可以利用多态性来管理实际派生类对象的生命周期,同时规避抽象基类带来的问题。这种方法允许灵活地将抽象类与 STL 容器结合使用,为抽象基类带来的限制提供了一个实用的解决方案。 性质我们为什么不能在 C++ 中声明 std::vector<AbstractClass> 的问题根源于抽象类的几个关键特性以及 STL 容器的要求。理解这些特性有助于阐明其中涉及的基本限制和挑战。
示例输出 DerivedClass1 doing something DerivedClass2 doing something 说明考虑到它作为一个抽象的基类,通过一个名为 `doSomething()` 的完全虚函数创建,因此直接构造 `AbstractClass` 似乎是不可行的。任何派生类都必须按照设计来实现此特定函数。抽象类还具有一个虚析构函数,用于确保在使用基类指针删除对象时执行创建类的析构函数。 我们收集了两个派生类,`DerivedClass1` 和 `DerivedClass2`,它们都以独特的方式实现了 `doSomething()` 算法。这些实现仅仅生成不同的消息,以显示每个生成的类如何以不同的方式响应方法调用。 在 `main` 函数中,`std::vector` 存储指向派生类组件的 `std::unique_ptr` 指针。 使用 `std::unique_ptr` 可确保动态分配对象的自动且异常安全的管理,并在对象超出作用域时处理它们的析构。 `std::make_unique` 函数创建 `DerivedClass1` 和 `DerivedClass2` 的实例,并将它们包装在 `std::unique_ptr` 中,然后将它们推入 vector。这使得 vector 能够管理这些对象的生命周期,同时保持代码的整洁并防止内存泄漏。 复杂度在 C++ 中尝试声明 `std::vector` 的操作是由抽象类的一些问题以及 `std::vector` 对其每个组件的规范所触发的。 抽象概念以及依赖实现 在 C++ 中,如果一个元素至少有一个纯虚函数(或通过将参数设置为 0 来声明的参数),则该元素可以被认为是抽象的。这个声明表明,虽然类定义了用户界面,但其行为尚未完全实现,因此无法直接创建。派生类必须提供这些纯虚函数的具体实现的约束对于面向对象编程中的抽象概念至关重要。 多态性和对象管理 为了处理抽象类的多态行为,通常的做法是使用指针或智能指针。这是因为指针可以引用派生类实例,从而允许 vector 通过这些指针间接存储和管理对象。通过在 vector 中存储指针,例如 `std::unique_ptr<AbstractClass>` 或 `std::shared_ptr<AbstractClass>`,我们回避了 vector 本身处理直接对象管理复杂性的需求。 C++ 中 `std::vector<AbstractClass>` 的限制无法在 C++ 中声明 `std::vector<AbstractClass>` 的限制源于与抽象类以及 `std::vector` 所需操作相关的几个基本约束。以下是这些限制的详细介绍:
结论在 C++ 中,我们不能声明 `std::vector<AbstractClass>`,因为 `std::vector` 要求其元素是可复制和可移动的,而抽象类不满足这一约束。抽象类定义为至少有一个纯虚函数,因此不能直接实例化。这个特性本身使得 `std::vector` 无法管理此类元素的集合,因为使用抽象类进行复制和移动等 vector 操作将不可行。 总而言之,虽然由于类的抽象性质无法直接使用 `std::vector<AbstractClass>`,但通过使用指针、智能指针或替代容器设计,可以有效地管理和操作派生自抽象类的对象的集合。这些方法在遵守标准容器要求的同时,保持了多态性的灵活性和强大功能。 下一话题使用 C++ 查找 Pell 数 |
C++ 标准库提供了各种流类,便于格式化的输入和输出操作。C++20 中较新的一个添加项是 `std::basic_ospanstream`。它是 `
阅读 4 分钟
引言:理解定量序列结构的问题可以称为算法问题解决。一种这样的结构是“山谷”,即一个序列先减少到其最小值,然后再次增加。这些类型的问题在各种领域都有应用,例如...
阅读 8 分钟
在 C++ 中,IQR 代表四分位距,是一个统计度量,它关注数据集中间部分的评分。它可以代数地表示为两个变量的减法:IQR = Q3−Q1,其中 IQR 是...
5 分钟阅读
在 C++ 中,标准模板库 (STL) 是一组容器库以及实现处理集合中数据的各种算法的关联函数。用于操作向量的两个常用组件是 std::erase 和 std::vector::remove。尽管两者都用于...
阅读 4 分钟
在现代 C++ 中,有效的内存管理对于创建高性能应用程序至关重要。`std::uninitialized_value_construct` 就是这样一个函数,它能够构建未初始化内存中的对象。本文解释了 `std::uninitialized_value_construct`,说明了它的功能,并提供了一些有用的示例来演示如何使用它。C++ 标准库...
5 分钟阅读
金矿问题展示了动态编程派生的基本思想,包括优化、决策和状态转换概念。在现实世界问题中,问题的基于网格的布局和移动限制使得可以使用该问题来帮助执行诸如资源规划等任务...
14 分钟阅读
在本文中,我们将讨论 C++ 中指针的应用。但在讨论其应用之前,我们必须了解指针。“C++ 指针”简介:指针是 C++ 的重要元素,它支持复杂的内存操作和资源动态分配。本质上,一个...
阅读 4 分钟
给定一个数字 n,翻转数字,使得新数字的二进制展开的首位和末位相同;也就是说,如果最初分配的位是 1,则翻转的位应分配为 0,依此类推。这是...
阅读 4 分钟
C++ 中的“K'th Boom Number”是指在满足特定要求(例如包含预定义的数字(如“7”)或可被整除)的过程中生成的第 K 个数字。一种方法会逐个生成数字,直到条件得到验证...
阅读 4 分钟
在 C++ 中,一个数字的数字既不严格递增也不严格递减,则称为“弹跳数”。例如,134468 递增,987654 递减,而 155349 弹跳,它同时表现出这两种趋势。位数少于 100 的数字不会弹跳。一个数字可以被认为是...
5 分钟阅读
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India