有趣的C ++抽象函数

时间:2008-12-13 09:43:18

标签: c++ internals

为什么会这样?

当您在c ++ Ex中创建抽象类时: A类(具有纯虚函数) 之后 B类继承自 A

如果 A类具有名为 A()的构造函数 假设我创建了一个对象 B类,那么编译器首先初始化基类,即 A类,然后初始化类B < / strong>那么.......?

首先,我们不能在没有Object的情况下访问任何类的构造函数,那么如果我们不能创建抽象类的对象,它是如何初始化抽象类的构造函数的。

5 个答案:

答案 0 :(得分:8)

快速回答:构造函数很特殊。

当A的构造函数仍在运行时,正在构造的对象尚未真正属于A类。它仍在构造中。当构造函数完成时,它现在是A。

对于派生的B,它是相同的.A的构造函数首先运行。现在它是A.然后B的构造函数开始运行。在此期间,对象仍然是A。只有当B的构造函数完成时,它才会成为B。

您可以通过尝试从构造函数调用纯虚函数来验证这一点。如果函数在A中定义,并且B的构造函数调用它,则会出现运行时错误,而不是运行B的覆盖,因为该对象尚未出现类型B.

由于纯虚函数,编译器不允许生成构造A的代码。但它会生成代码来构造A作为构建B的过程的一部分。这里没有任何魔法。你不能构造A的规则是由语言规则强加的,而不是物理规则。语言在构建B对象的特殊情况下提升了规则。

答案 1 :(得分:4)

class A是抽象的,但class B不是。为了构造class B,它必须实现class A的所有纯虚拟成员函数。

class A
{
public:
    A() {}
    virtual ~A() {}
    virtual void foo() = 0; // pure virtual
    int i;
};


class B : public A
{
public:
    B() {}
    virtual ~B() {}
    virtual void foo() {}
    int j;
};

A类布局可能是这样的:

+---------+     +---------+
| vftable | --> | ~A()    | --> address of A::~A()
+---------+     +---------+
| i       |     | foo()   | --> NULL, pure virtual
+---------+     +---------+

B类布局可能是这样的:

+---------+     +---------+
| vftable | --> | ~B()    | --> address of B::~B()
+---------+     +---------+
| i       |     | foo()   | --> address of B::foo()
+---------+     +---------+
| j       |
+---------+

答案 2 :(得分:1)

struct A {
  A(int x) {..}
  virtual void do() = 0;
};

struct B : public A {
   B() : A(13) {}      // <--- there you see how we give params to A c'tor
   virtual void do() {..}
};

答案 3 :(得分:0)

 And if class A has constructor called A() suppose i created an
 Object of class B then the compiler initializes the base class
 first i.e.class A and then initialize the class B
 Then.......?

实际上你的方法是错误的:

当你创建B类的对象时,会调用B的构造函数 如果您没有指定B构造函数如何调用A构造函数,那么编译器将自动插入初始化程序列表中的第一个操作,调用A的默认构造函数。

如果您不想使用默认构造函数,则必须将对相应A构造函数的调用显式地作为初始化列表中的第一个元素。

当A的构造完成后,B的构造将继续。

First thing is we can not access a constructor of any class without an Object
then how it is initialize the constructor of abstract class if we can not create
an object of abstract class .

你说上面就好像你认为A和B不同。 B类的对象也是A类的对象。整个对象是有效的。整个对象属于B类,但它包含(作为同一对象的一部分)来自A类的所有信息。

答案 4 :(得分:0)

仅仅因为你无法直接实例化类A并不意味着实例化类A是不可能的。您不能实例化A因为编译器知道A是抽象的并且拒绝您尝试直接实例化A的任何代码。它禁止这样的代码:

A a;
new A();

使类抽象的原因是它具有纯虚方法。但是,没有任何东西可以阻止这样的类被实例化。 C ++标准简单地说它是不允许的。编译器完全能够生成实例化抽象类的指令。它所要做的就是保留适量的内存,然后调用构造函数,就像对非抽象类一样。

当您实例化B时,该类的所有内存都会立即被分配。由于所有字节都在那里,因此在那里基本上有一个A实例,准备由构造函数初始化。 (但请注意,在A构造函数完成运行之后 A构造函数运行时,内存不会被正式视为A类型的对象。)B构造函数运行,然后运行{{1}}构造函数。