为什么会这样?
当您在c ++中创建抽象类时:从类A继承类B之后的类A(具有纯虚函数)
如果A 类 有一个名为A()的构造函数, 假设我创建了B 类的一个对象 ,那么编译器首先初始化基类,即A 类,然后初始化B 类然后.......?
首先是我们不能访问没有 Object 的任何类的构造函数,那么如果我们不能创建抽象类的对象,它是如何初始化抽象类的构造函数的。
快速回答:构造函数是特殊的。
当 A 的构造函数仍在运行时,则正在构造的对象还不是真正的 A 类型。它仍在构造中。当构造函数完成时,它现在是一个 A。
派生的 B 也是如此。 A 的构造函数首先运行。现在它是一个 A。然后 B 的构造函数开始运行。在此期间,对象仍然是真正的 A。只有当 B 的构造函数完成时,它才会成为 B。
您可以通过尝试从构造函数调用纯虚函数来验证这一点。如果函数在 A 中定义,并且 B 的构造函数调用了它,则会出现运行时错误,而不是运行 B 的覆盖,因为对象还不是 B 类型。
由于纯虚函数,编译器将不允许您生成将构造 A 的代码。但它会生成代码来构造 A 作为构造 B 的过程的一部分。这并不涉及任何魔法。不能构造 A 的规则是语言规则而不是物理学强加的。在构造 B 的对象的特殊情况下,该语言提升了该规则。
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 类布局可能是这样的:
+---------+ +---------+ | 可变表 | --> | 〜A()| --> A::~A() 的地址 +---------+ +---------+ | 我 | | 富()| --> NULL,纯虚拟 +---------+ +---------+
B 类布局可能是这样的:
+---------+ +---------+ | 可变表 | --> | 〜B()| --> B::~B() 的地址 +---------+ +---------+ | 我 | | 富()| --> B::foo() 的地址 +---------+ +---------+ | j | +----------+
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() {..}
};
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 类的所有信息。
不能直接实例化 classA
并不意味着不能实例化 class A
。您不允许实例化A
,因为编译器知道这A
是抽象的,并拒绝您编写的任何试图直接实例化的代码A
。它禁止这样的代码:
A a;
new A();
使类抽象的原因在于它具有纯虚方法。但是,没有什么本质上阻止这样一个类被实例化。C++ 标准只是简单地说这是不允许的。编译器完全能够生成指令来实例化一个抽象类。它所要做的就是保留适量的内存,然后调用构造函数,就像它对非抽象类一样。
当您实例化时B
,该类的所有内存都会立即分配。由于所有字节都在那里,因此那里基本上有一个A
实例,准备好由构造函数初始化。(但请注意,在构造函数完成运行A
之前,内存不会被正式视为类型对象。)构造函数运行,然后构造函数运行。A
A
B