为什么我们不能用抽象类创建容器?

时间:2017-07-22 02:12:27

标签: c++ templates containers

我试图创建抽象类的向量,但它给了我编译错误。代码是:

    class Base 
    {
    public :
        int _b; 
        virtual void virtualFunc() = 0;
    };

    int _tmain(int argc, _TCHAR* argv[])
    {
        std::vector<Base> vec;
    }

我得到的编译错误是:

error C2259: 'B' : cannot instantiate abstract class due to following members:
'void B::virtualFunc(void)' : is abstract

1)我不明白为什么我会去错误是因为vector会尝试调用构造函数?这是值得传递的东西吗? 2)模板功能也是同样的行为吗?

5 个答案:

答案 0 :(得分:4)

  

1)我不明白为什么我去错误是因为矢量会尝试   调用构造函数?

是 - 在内部,向量需要分配一个对象数组来保存您的数据,即它会尝试执行以下操作:

this->dataItems = new Base[10];

...但它无法做到这一点,因为Base是一个抽象类,因此可能无法直接实例化(在数组中或其他任何地方)。因此错误。

  

是否可以通过值传递?

不是直接的,但如果您的目标是拥有Base的各种子类的对象向量,那么您可能想要使用:

std::vector< std::shared_ptr<Base> > vec;

......相反。然后你可以做例如:

vec.push_back(new Derived1());  // where Derived1 is a subclass of Base
vec.push_back(new Derived2());  // where Derived2 is another subclass of Base
vec[0]->virtualFunc();   // calls Derived1::virtualFunc()
vec[1]->virtualFunc();   // calls Derived2::virtualFunc()

这将起作用,因为向量的内部数组只是一个智能指针数组(非抽象且所有类型相同)。

答案 1 :(得分:2)

您无法直接实例化抽象类,因此抽象类的向量无法工作。

但是,如果您坚持,可以使用指针来执行此操作。

std::vector<std::unique_ptr<Base>> vec;

当unique_ptr超出范围时,它将自动为您删除内存。

确保使用unique_ptr而不是原始指针,然后您不必担心内存释放。

答案 2 :(得分:1)

C ++不允许您创建抽象类的一个实例。所以,如果你不能创造一个物体,你将如何制作一个物体容器?

这样想。动物是一种抽象。狗是一种动物,因此是动物的一个子类。 Fido是Dog的特殊对象。

如果没有指定Dog,Cat,Elephant或其他动物,则无法创建Animal类型的对象。因此,你不能制作一个由动物园组成的动物园,但是你可以拥有一个动物园,里面有一个特定的大象,一个粒子虎,一个特定的大猩猩,等等。 / p>

你可能想要的是指向Base的指针容器。

std::vector< Base * > vec;

或者更好的是,智能的容器 - 指向Base。

typedef std::shared_ptr< Base > BasePtr;
std::vector< BasePtr > vec;

答案 3 :(得分:1)

我无法使用您的代码重现您的错误。

以下编译:

class Base
{
public :
   int _b;
   virtual void virtualFunc() = 0;
};

int main(int , char**)
{
   std::vector<Base> vec;
   return(0);
}

我的编译器发出以下警告:

R02: dumy506.cc
rm -f dumy506
g++-5 -m64  -O3 -ggdb -std=c++14 -Wall -Wextra -Wshadow -Wnon-virtual-dtor -pedantic -Wcast-align -Wcast-qual -Wconversion -Wpointer-arith -Wunused -Woverloaded-virtual   -O0   dumy506.cc  -o dumy506  -L../../bag -lbag_i686 -lposix_i686 -lrt -pthread

dumy506.cc:15:11: warning: ‘class Base’ has virtual functions and accessible non-virtual destructor [-Wnon-virtual-dtor]
     class Base

我可以通过添加虚拟dtor来清除此警告

class Base
{
public :
   virtual ~Base() = default;

   int _b;
   virtual void virtualFunc() = 0;
};

int main(int , char**)
{
     std::vector<Base> vec;
     return(0);
}

根据&#34; http://en.cppreference.com/w/cpp/container/vector/vector&#34;,&#34;默认构造函数。构造一个空容器。&#34;

这表示您的代码应该尝试创建任何元素。

纯粹的方法&#39;编译错误仅在我尝试实例化要安装到vec中的元素时发生。

int main(int , char**)
{
   std::vector<Base> vec;
   Base b;                // <<< pure method error detected here
   vec.push_back(b);
   return(0);
}


dumy506.cc:31:12: error: cannot declare variable ‘b’ to be of abstract type ‘Base’
       Base b;
            ^
dumy506.cc:15:11: note:   because the following virtual functions are pure within ‘Base’:
     class Base
           ^
dumy506.cc:22:21: note:     virtual void Base::virtualFunc()
        virtual void virtualFunc() = 0;

2017年7月22日更新

今天,在我的系统上,vec.reserve()触发了一个由于纯函数而失败的内存分配。

或许OP的实现(和其他2个答案?)尝试在ctor期间分配一些最小数量(?)的元素,与cppreference.com相反。

也许cppreference.com是错误的,或者要求是移动&#39;。

最终更新

  

1)我不明白为什么我去[原文如此]错误是因为矢量会尝试   调用构造函数?

没有。可以创建一个空矢量。没有B被实例化。

  

是否可以通过值传递?

我想不是。

  

2)模板函数也是同样的行为吗?

您尚未描述已发布代码的行为。

我的系统:Ubuntu 15.10,64位

编译器:

〜$ g ++ - 5 --version g ++ - 5(Ubuntu 5.2.1-23ubuntu1~15.10)5.2.1 20151028

答案 4 :(得分:0)

T所有容器中最基本的要求是T是值类型,您可以创建它的实例

根据定义,声明不能创建抽象类的实例。

根据定义,模板是元函数和元类:它们通过填充给定的模板参数来实例化。它们是创建函数和类的工具,但它们不是函数和类。当使用违反规范的模板参数时,将生成不正确的函数或类,并且错误消息将显示一堆instanciation,有点像可以检查调用abort()的进程的事后转储函数调用栈。

错误消息的确切性质取决于容器的实现细节。 这是C ++模板非常难看的本质。它本质上是一种高级宏语言。