调整std :: vector <abstractclass *>的大小

时间:2016-09-18 19:14:39

标签: c++ vector constructor abstract-class

我的理解是,我们永远不能在C++中实例化一个抽象类,或者在Java中同样实例化一个接口。这是有道理的,因为我们有&#34;纯虚拟&#34;没有提供实现的函数,因此我们只能实例化这个类/接口的子类,这些子类遵循抽象类形成的契约。请考虑以下代码:

#include <iostream>
#include <vector>

using namespace std;

class AbstractClass {
public:
  AbstractClass() {
    cout << "Instantiating" << endl;
  }

  virtual void pureVirtualFunction() = 0;

  void testMe() {
    cout << "test" << endl;
  }
};

int main() {
  vector<AbstractClass*> v;
  v.resize(100);
  cout << v.size() << endl;
  v[0]->testMe();
  v[0]->pureVirtualFunction(); //segfault on my machine
  return 0;
}

当我在计算机上运行时,令我感到困惑的是,我实际上可以调整矢量大小。我一直认为std::vector::resize实例化了一些元素,因此调用了每个元素的构造函数,但是进一步的研究表明构造函数实际上并没有被调用(也很明显我的stdout没有显示100x&#34;实例化&# 34;字符串)。

因此,如果std::vector::resize为这些新对象分配空间,并允许我实际调用每个对象的方法,那么它们如何不完全实例化?我想我甚至无法在抽象类的向量上调用resize(),但我可以,因为它们没有完全初始化。有人能解释一下这里发生了什么吗?

编辑:

Brain fart..forgot指针的一个向量,当调整大小时,实际上并没有分配new个元素,因为可以在没有分配元素的情况下创建指针,但是......为什么我仍然可以调用一个成员函数指向未实例化的类的指针?

3 个答案:

答案 0 :(得分:2)

其他答案已经说出你的代码出了什么问题,我在这里回答编辑:

  

然而......为什么我仍然可以在指向a的指针上调用成员函数   没有实例化的类?

你的意思是这一部分:

  v[0]->testMe();
  v[0]->pureVirtualFunction(); //segfault on my machine

基本上,因为v[0]未指向有效对象,但尝试调用testMe()已经是未定义的行为。

它不是段错误的唯一原因是因为编译器重写了你的代码是不幸的。方法testMe()的主体根本不需要*this对象,因此编译器只需用cout调用替换它。因为没有尝试访问某些无效的this指针,所以还没有段错误。然后,当调用第二个方法时,编译器需要检查无效this指针的vtable,这会导致段错误。不要永远依赖于testMe()的行为,这仍然是未定义的行为,任何事情都可能发生。

答案 1 :(得分:2)

value_type的{​​{1}}为vector - 也就是说,该向量包含指针,可能是AbstractClass*,指向a的nullptr内存中AbstractClass派生或随机位置的有效实例。

vector::resize(N)创建N默认初始化元素,同样,向量的value_type*,因此它会创建N个实例nullptr

AbstractClass::testMe是非虚拟成员函数。因此,在引擎盖下,它只是一个普通函数,它将隐藏的this指针作为其第一个参数。

testMe的主体本身不访问抽象类的任何元素,因此它永远不会取消引用 this

因此

v[0]->testMe();

调用AbstractClass::testMe(nullptr, );,永不解除引用this

v[0]->pureVirtualFunction(); //segfault on my machine

尝试取消引用nullptr以找到v[0] s vtable =&gt;崩溃。

答案 2 :(得分:0)

您制作了AbstractClass *的向量,而不是AbstractClass

可以在没有指向对象的情况下创建指针。

由于函数是虚拟的,这些指针可以指向派生类&#39;不再是抽象的对象,所以调用是合法的 只有当您最终执行它时,系统才会跳过vptr表中的null并转储。