需要一个从向量派生的向量

Posted

技术标签:

【中文标题】需要一个从向量派生的向量【英文标题】:Need a vector that derives from a vector 【发布时间】:2009-11-03 18:20:40 【问题描述】:

考虑这个简单的代码:

class A 
;

class V1: vector<A *>
  // my nice functions
;

如果我有一个 V1 的实例,那么任何从 A 派生的对象都可以插入到向量中,在这里可以。

现在,假设我有两个名为 B 和 C 的简单类都派生自 A; 如果我有一个 V1 的实例,那么 B 和 C 的指针都可以插入到这个向量中,我想这是正确的吗?

如果是这样,我如何从 V1 派生一个向量以确保只插入 B 指针? 我正在考虑使用模板,但在这种情况下,我已经知道类的基础,并且在模板中你可以使用任何东西,对吧?

不知道我是否清楚,我的英语没有帮助...... 我是否必须重写 push_back 和其他函数来检查模板参数是否从 A 派生?

请不要谈论我正在使用的提升或语法等......我真的只是想了解这个的概念......我还不清楚。我对此有一些答案,但我想它们涉及太多演员来检查东西,我来这里是想知道是否有更好的答案......

谢谢! 乔纳森

ps:你们能回答我放的cmets吗?有时我在这里问一些东西,然后最好的回答者来了,然后就不回来了:(。或者我应该问另一个问题而不是评论提问?

【问题讨论】:

明确一点,你B派生自A,但你不想在V1中存储指向B对象的指针,只存储指向A对象的指针? 对不起...我有一个名为 A 的抽象类,然后我将有几个从 A 派生的类,例如 B 和 C。然后会有一个向量,每个(或大多数)派生自A. 像vector、vector,但我想创建一个已经有很多函数的类,这些函数使用A类的成员和例程,并且不想为向量重写这些东西B和C的……我还不清楚吗?再次抱歉=[ 【参考方案1】:

从您的示例中不清楚是否需要继承。您可能还没有意识到它很危险,因为 std::vector 没有虚拟析构函数。这意味着在删除指向基类的指针时不会调用 V1 的析构函数,并且您最终可能会泄漏内存/资源。请参阅here 了解更多信息。

class A 
;

class V1: vector<A *>
  // my nice functions
;

如果我有一个 V1 的实例,那么任何从 A 派生的对象都可以是 插入向量中,这里ok。

是的,正确。

现在,假设我有两个简单的 名为 B 和 C 的类都派生 来自 A;如果我有一个 V1 实例, 那么 B 和 C 的两个指针都可以 插入这个向量,我猜 这样确认合适吗?

是的,正确。

如果是这样,我如何从 V1 以确保只有 B 指针是 插入?我在考虑使用 模板,但在这种情况下,我已经 知道类的基础并在 模板你可以用任何东西,对吧?

为什么不使用

std::vector<B*> m_bVector;

对于这种情况?以下是它的工作原理:

B* bInstance = new B();
A* aInstance = new A();
m_bVector.push_back(bInstance);
m_bVector.push_back(aInstance); //< compiler error

也许您有充分的理由从vector继承,但我现在看不到...如果您需要添加功能,最好让V1包装std::vector,即:

class V1

private:
   std::vector<A*> m_aVec;
public:
   // use AVec

【讨论】:

我有几个函数在逻辑上不能在同一个向量中包含不同的对象,即使它们派生自同一个类。但它们必须从 A 派生,所以我可以使用 A 成员和函数... 阅读您的帖子并思考您所写的内容...是的,我可以将矢量包装在课堂内,如果需要,使用外部模板 “它们必须从 A 派生,以便我可以使用 A 成员和函数”。我建议重新设计:将 V1 编写为模板类而不是普通类。使其成为“容器适配器”,例如std::stack,这意味着它有一个向量(或其他容器)作为成员,并且具有您需要的自己的功能。然后你可以创建一个V1&lt;A*, vector&gt;V1&lt;B*, vector&gt;,或者其他的。 这意味着 V1 的析构函数 不完全准确。只有通过指向基类的指针销毁析构函数时,才会调用析构函数。【参考方案2】:

一般来说,您不应该从 STL 容器派生。为什么不在class V1 中使用vector&lt;A*&gt; 成员?

【讨论】:

好的,即使是这样,我怎样才能确保模板只有B指针(在上面的情况下)? typedef vector&lt;B*&gt; VectorOfBs; ? 但是我已经有一个类,它的函数使用 A 成员和例程的向量,所以 vector 需要这些函数【参考方案3】:

如果你想在你的向量中存储 B 指针,最好的解决方案是从

std::vector<B*>

或者,如果您希望将您的类也与 A 指针一起使用,请制作一个模板

template<typename T>
class MyVec : public std::vector<T> 
;

MyVec<A*> va; // stores A* and B*
MyVec<B*> vb; // stores B* only

【讨论】:

是的,但在模板情况下,我如何确保 T 派生自 A?在 C# 中,它将是“where”关键字。比如:类 S: List 其中 T: A 。我的问题是我是否必须使用演员表来检查 @Jonhathan:如果 MyVec 的函数使用 A 的接口,那么在没有所需接口的类型上实例化 MyVec 将根本无法编译。 你能给我举个例子吗?无法正确理解。或者我去谷歌搜索的这个名字 嗯,不知道我能不能在评论中写出来……让我们试试:class A public: void bar()=0;模板 class V1public: void foo(T*)T->bar();; B类:公共A; C类公共:无效baz(); V1 vb; //OK,编译正常 vb.foo(); V1 vc; vc.foo(); //哎呀!错误:“bar()”不是 C 的成员 如果您作为模板参数提供的类不符合模板条件编译将失败。如果确实如此,为什么不允许制作此类的向量。这是模板的概念——如果有合适的方法让它与模板一起工作。如果 MyVec 无法正常工作,请不要创建它。【参考方案4】:

如果是这样,我如何从 V1 派生一个向量以确保只插入 B 指针?

撇开您不应该从 STL 容器继承(对于 number of reasons 这可能并不明显),答案是您不应该继承。反正也不是。

您可以在运行时断言只能插入B*

if(!dynamic_cast<B*>(item))
    return false;

但这依赖于 C++ 的 RTTI 支持,通常非常慢。您可以改为使用某种“滚动您自己的”RTTI 接口(,一个返回标识类的枚举的函数),或者可能是 Boost 的 static assert 测试 typeof 对象.

我的偏好是这样的:

template<typename T>
class V1 
private:
    std::vector<T*> _vec;
// ...
;

然后使用对您的用例有意义的T 类型进行实例化。

但是,如果您的案例依赖于有时全是 B*s,有时全是 A*s,那么我会认为您的设计很糟糕,应该重新考虑。

【讨论】:

大声笑 =p。这不是我的情况,呵呵,向量永远不会有混合类型,但我将拥有使用该实例基础的功能,例如加载 xml 数据等 那么我认为你的设计是错误的,你使用继承不当。

以上是关于需要一个从向量派生的向量的主要内容,如果未能解决你的问题,请参考以下文章

C++ - 从向量中获取派生类变量

从基类类型的向量访问派生类方法

如何通过派生类函数从基类更改向量

如何从基类向量中获取派生类变量?

C ++跨类访问基对象向量中的派生对象的引用

如何使用多态性从基类访问派生类向量成员?