为什么我们不能声明 std::vector?
在花了相当长的时间进行 C# 开发后,我注意到,如果您声明一个抽象类以将其用作接口,则无法实例化该抽象类的向量来存储子类的实例。
#pragma once
#include <iostream>
#include <vector>
using namespace std;
class IFunnyInterface
{
public:
virtual void IamFunny() = 0;
};
class FunnyImpl: IFunnyInterface
{
public:
virtual void IamFunny()
{
cout << "<INSERT JOKE HERE>";
}
};
class FunnyContainer
{
private:
std::vector <IFunnyInterface> funnyItems;
};
声明抽象类向量的行在 MS VS2005 中导致此错误:
error C2259: 'IFunnyInterface' : cannot instantiate abstract class
我看到一个明显的解决方法,即将 IFunnyInterface 替换为以下内容:
class IFunnyInterface
{
public:
virtual void IamFunny()
{
throw new std::exception("not implemented");
}
};
这是 C++ 方面可接受的解决方法吗? 如果没有,是否有像 boost 这样的第三方库可以帮助我解决这个问题?
感谢您阅读本文!
安东尼
Having spent quite some time developping in C#, I noticed that if you declare an abstract class for the purpose of using it as an interface you cannot instantiate a vector of this abstract class to store instances of the children classes.
#pragma once
#include <iostream>
#include <vector>
using namespace std;
class IFunnyInterface
{
public:
virtual void IamFunny() = 0;
};
class FunnyImpl: IFunnyInterface
{
public:
virtual void IamFunny()
{
cout << "<INSERT JOKE HERE>";
}
};
class FunnyContainer
{
private:
std::vector <IFunnyInterface> funnyItems;
};
The line declaring the vector of abstract class causes this error in MS VS2005:
error C2259: 'IFunnyInterface' : cannot instantiate abstract class
I see an obvious workaround, which is to replace IFunnyInterface with the following:
class IFunnyInterface
{
public:
virtual void IamFunny()
{
throw new std::exception("not implemented");
}
};
Is this an acceptable workaround C++ wise ?
If not, is there any third party library like boost which could help me to get around this ?
Thank you for reading this !
Anthony
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您无法实例化抽象类,因此抽象类向量无法工作。
但是,您可以使用指向抽象类的指针向量:
这也允许您实际使用多态行为 - 即使该类不是抽象的,按值存储也会导致 对象切片。
You can't instantiate abstract classes, thus a vector of abstract classes can't work.
You can however use a vector of pointers to abstract classes:
This also allows you to actually use polymorphic behaviour - even if the class wasn't abstract, storing by value would lead to the problem of object slicing.
您无法创建抽象类类型的向量,因为您无法创建抽象类的实例,并且 C++ 标准库容器(如 std::vector )存储值(即实例)。如果你想这样做,你将必须创建一个指向抽象类类型的指针向量。
您的解决方法将不起作用,因为虚拟函数(这就是您首先需要抽象类的原因)仅在通过指针或引用调用时才起作用。您也无法创建引用向量,因此这是必须使用指针向量的第二个原因。
您应该意识到 C++ 和 C# 几乎没有共同点。如果您打算学习 C++,您应该将其视为从头开始,并阅读良好的专用 C++ 教程,例如 Accelerated C++,作者:Koenig 和 Moo。
You can't create a vector of an abstract class type because you cannot create instances of an abstract class, and C++ Standard Library containers like std::vector store values (i.e. instances). If you want to do this, you will have to create a vector of pointers to the abstract class type.
Your workround would not work because virtual functions (which is why you want the abstract class in the first place) only work when called through pointers or references. You cannot create vectors of references either, so this is a second reason why you must use a vector of pointers.
You should realise that C++ and C# have very little in common. If you are intending to learn C++, you should think of it as starting from scratch, and read a good dedicated C++ tutorial such as Accelerated C++ by Koenig and Moo.
在这种情况下,我们甚至不能使用这样的代码:
或者
因为FunnyImpl和IFunnyInterface之间不存在IS A关系,并且由于私有继承,FunnyImpl和IFunnyInterface之间不存在隐式转换。
您应该按如下方式更新您的代码:
In this case we can't use even this code:
or
Because there is no IS A relationship between FunnyImpl and IFunnyInterface and there is no implicit convertion between FUnnyImpl and IFunnyInterface because of private inheritance.
You should update your code as follows:
传统的替代方案是使用指针向量,如前所述。
对于那些欣赏的人来说,
Boost
附带了一个非常有趣的库:Pointer Containers
,它非常适合该任务,并将您从指针隐含的各种问题中解放出来:请注意,无论是在性能还是接口方面,这都明显优于智能指针的
向量
。现在,有第三种选择,那就是改变你的层次结构。为了更好地隔离用户,我多次看到使用了以下模式:
这非常简单,是通过
Strategy
模式丰富的Pimpl
习惯用法的变体。当然,它仅在您不希望直接操作“真实”对象并且涉及深度复制的情况下才有效。所以这可能不是你所希望的。
The traditional alternative is to use a
vector
of pointers, like already noted.For those who appreciate,
Boost
comes with a very interesting library:Pointer Containers
which is perfectly suited for the task and frees you from the various problems implied by pointers:Note that this is significantly better than a
vector
of smart pointers, both in terms of performance and interface.Now, there is a 3rd alternative, which is to change your hierarchy. For better insulation of the user, I have seen a number of times the following pattern used:
This is quite straightforward, and a variation of the
Pimpl
idiom enriched by aStrategy
pattern.It works, of course, only in the case where you do not wish to manipulate the "true" objects directly, and involves deep-copy. So it may not be what you wish.
因为要调整向量的大小,您需要使用默认构造函数和类的大小,这反过来又要求它是具体的。
您可以按照其他建议使用指针。
Because to resize a vector you need to use the default constructor and the size of the class, which in turn requires it to be concrete.
You can use a pointer as other suggested.
std::vector 将尝试分配内存来包含您的类型。如果您的类是纯虚拟的,则向量无法知道它必须分配的类的大小。
我认为通过您的解决方法,您将能够编译一个
vector
但您将无法在其中操作unnyImpl。例如,如果 IFunnyInterface (抽象类)的大小为 20(我真的不知道),而FunnyImpl 的大小为 30,因为它有更多的成员和代码,那么您最终将尝试将 30 放入 20 的向量中。解决方案是使用“new”在堆上分配内存并将指针存储在
vector
中std::vector will try to allocate memory to contain your type. If your class is purely virtual, the vector cannot know the size of the class it will have to allocate.
I think that with your workaround, you will be able to compile a
vector<IFunnyInterface>
but you won't be able to manipulate FunnyImpl inside of it. For example if IFunnyInterface (abstract class) is of size 20 (i dont really know) and FunnyImpl is of size 30 because it has more members and code, you will end up trying to fit 30 into your vector of 20The solution would be to allocate memory on the heap with "new" and store pointers in
vector<IFunnyInterface*>
我认为这个真正令人悲伤的限制的根本原因是构造函数不能虚拟。因此,编译器无法生成在编译时不知道对象时间的情况下复制对象的代码。
I think that the root cause of this really sad limitation is the fact that constructors can not virtual. Thereof compiler can not generate code which copy the object without knowing its time in the compile time.