Blu*_*rin 78 c++ abstract-class stl
花了很长时间在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;
};
Run Code Online (Sandbox Code Playgroud)
声明抽象类向量的行在MS VS2005中导致此错误:
error C2259: 'IFunnyInterface' : cannot instantiate abstract class
Run Code Online (Sandbox Code Playgroud)
我看到一个明显的解决方法,即用以下内容替换IFunnyInterface:
class IFunnyInterface
{
public:
virtual void IamFunny()
{
throw new std::exception("not implemented");
}
};
Run Code Online (Sandbox Code Playgroud)
这是一个可接受的解决方案C++明智吗?如果没有,是否有像boost这样的第三方库可以帮我解决这个问题?
谢谢您阅读此篇 !
安东尼
Geo*_*che 116
您无法实例化抽象类,因此抽象类的向量无法工作.
但是,您可以使用指针向量来抽象类:
std::vector<IFunnyInterface*> ifVec;
Run Code Online (Sandbox Code Playgroud)
这也允许您实际使用多态行为 - 即使该类不是抽象的,按值存储也会导致对象切片的问题.
小智 21
您无法创建抽象类类型的向量,因为您无法创建抽象类的实例,以及像std :: vector存储值(即实例)的C++标准库容器.如果要执行此操作,则必须创建指向抽象类类型的指针向量.
您的workround不起作用,因为虚函数(这就是您首先想要抽象类的原因)仅在通过指针或引用调用时才起作用.您也无法创建引用向量,因此这是您必须使用指针向量的第二个原因.
您应该意识到C++和C#几乎没有共同之处.如果您打算学习C++,您应该将其视为从头开始,并阅读一篇很好的专用C++教程,例如Koenig和Moo的Accelerated C++.
在这种情况下,我们甚至无法使用此代码:
std::vector <IFunnyInterface*> funnyItems;
Run Code Online (Sandbox Code Playgroud)
要么
std::vector <std::tr1::shared_ptr<IFunnyInterface> > funnyItems;
Run Code Online (Sandbox Code Playgroud)
因为FunnyImpl和IFunnyInterface之间没有IS A关系,并且由于私有继承而在FUnnyImpl和IFunnyInterface之间没有隐式转换.
您应该按如下方式更新代码:
class IFunnyInterface
{
public:
virtual void IamFunny() = 0;
};
class FunnyImpl: public IFunnyInterface
{
public:
virtual void IamFunny()
{
cout << "<INSERT JOKE HERE>";
}
};
Run Code Online (Sandbox Code Playgroud)
传统的替代方案是使用vector
指针,如已经指出的那样.
对于那些欣赏的人来说,Boost
它带有一个非常有趣的库:Pointer Containers
它非常适合于任务,并使您免受指针隐含的各种问题:
请注意,这vector
在性能和界面方面明显优于智能指针.
现在,还有第三种选择,即改变您的层次结构.为了更好地隔离用户,我已经多次看到使用以下模式:
class IClass;
class MyClass
{
public:
typedef enum { Var1, Var2 } Type;
explicit MyClass(Type type);
int foo();
int bar();
private:
IClass* m_impl;
};
struct IClass
{
virtual ~IClass();
virtual int foo();
virtual int bar();
};
class MyClass1: public IClass { .. };
class MyClass2: public IClass { .. };
Run Code Online (Sandbox Code Playgroud)
这非常简单,并且Pimpl
通过Strategy
模式丰富了成语的变体.
当然,它仅适用于您不希望直接操作"真实"对象并涉及深层复制的情况.所以它可能不是你想要的.