C++ 有趣的C++;抽象函数
为什么会发生这种情况 当C++在C++中创建抽象类:<强>类A<强>(具有纯虚函数) 之后,B类继承自A类 如果类A的构造函数调用了A() 假设我创建了类B的对象,那么编译器首先初始化基类,即类A,然后初始化类B,然后C++ 有趣的C++;抽象函数,c++,internals,C++,Internals,为什么会发生这种情况 当C++在C++中创建抽象类:类A(具有纯虚函数) 之后,B类继承自A类 如果类A的构造函数调用了A() 假设我创建了类B的对象,那么编译器首先初始化基类,即类A,然后初始化类B,然后 首先,如果没有对象,我们不能访问任何类的构造函数,那么如果我们不能创建抽象类的对象,那么如何初始化抽象类的构造函数呢。为了构造类B,它必须实现类A的所有纯虚拟成员函数 class A { public: A() {} virtual ~A() {} virtual v
首先,如果没有对象,我们不能访问任何类的构造函数,那么如果我们不能创建抽象类的对象,那么如何初始化抽象类的构造函数呢。为了构造
类B
,它必须实现类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;
};
类布局可以是这样的:
+---------+ +---------+
| vftable | --> | ~A() | --> address of A::~A()
+---------+ +---------+
| i | | foo() | --> NULL, pure virtual
+---------+ +---------+
+---------+ +---------+
| vftable | --> | ~B() | --> address of B::~B()
+---------+ +---------+
| i | | foo() | --> address of B::foo()
+---------+ +---------+
| j |
+---------+
A a;
new A();
+---------+ +---------+
|vftable |-->| ~A()|-->A的地址::~A()
+---------+ +---------+
|i | | foo()|-->NULL,纯虚拟
+---------+ +---------+
B类布局可以是这样的:
+---------+ +---------+
| vftable | --> | ~A() | --> address of A::~A()
+---------+ +---------+
| i | | foo() | --> NULL, pure virtual
+---------+ +---------+
+---------+ +---------+
| vftable | --> | ~B() | --> address of B::~B()
+---------+ +---------+
| i | | foo() | --> address of B::foo()
+---------+ +---------+
| j |
+---------+
A a;
new A();
+---------+ +---------+
|vftable |-->| ~B()|-->B的地址::~B()
+---------+ +---------+
|i | | foo()|-->B::foo()的地址
+---------+ +---------+
|j|
+---------+
快速回答:构造函数是特殊的 当A的构造函数仍在运行时,则正在构造的对象还不是真正的类型A。它仍在构造中。当构造函数完成时,它现在是A 对于派生B也是一样的。首先运行A的构造函数。现在是A,然后B的构造函数开始运行。在此期间,对象仍然是A。只有当B的构造函数完成时,它才成为B 您可以通过尝试从构造函数调用纯虚函数来验证这一点。如果函数是在A中定义的,而B的构造函数调用它,则会出现运行时错误,而不是运行B的重写,因为对象还不是B类型 由于纯虚函数,编译器将不允许您生成将构造A的代码。但它将生成代码来构造A,作为构造A B过程的一部分。这其中没有魔法。不能构造A的规则是由语言规则而不是物理规则强加的。该语言在构造B的对象的特殊情况下解除了该规则。
struct A{
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() {..}
};
A(int x){..}
虚空do()=0;
};
结构B:公共A{
B():A(13){}//
事实上,你的想法是错误的:
创建类B的对象时,将调用类B的构造函数。
如果未指定B构造函数如何调用构造函数,则编译器将自动在初始值设定项列表中的第一个操作中插入对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 .
<>你把上面提到的东西看成是一个B和B不同的东西。B类的对象也是类A的对象。它是一个整体有效的对象。整个对象是B类,但这包含(作为同一对象的一部分)。所有来自类A的信息。仅仅因为不能直接实例化类A
并不意味着不可能实例化类A
。不允许实例化A
,因为编译器知道A
是抽象的,并且拒绝您编写的任何试图直接插入的代码tantiateA
。它禁止这样的代码:
+---------+ +---------+
| vftable | --> | ~A() | --> address of A::~A()
+---------+ +---------+
| i | | foo() | --> NULL, pure virtual
+---------+ +---------+
+---------+ +---------+
| vftable | --> | ~B() | --> address of B::~B()
+---------+ +---------+
| i | | foo() | --> address of B::foo()
+---------+ +---------+
| j |
+---------+
A a;
new A();
类抽象是指它有纯的虚拟方法。但是,本质上没有阻止此类类被实例化的。C++标准简单地说它是不允许的。编译器完全能够生成指令来实例化抽象类。它所要做的就是保留正确的内存量。然后调用构造函数,就像调用非抽象类一样
当您实例化B
时,该类的所有内存将立即分配。由于所有字节都在那里,因此那里基本上有一个A
实例,可以由构造函数初始化。(但请注意,在A
构造函数完成运行之前,内存不会被正式视为A
类型的对象。)A
构造函数运行,然后B
构造函数运行。谢谢你的回答,但我想知道它是如何创建抽象类的内部对象的?对于一个简单的问题,答案过于复杂。也许,我先做了一个简单的回答,但那没有回答Darshan的问题。在尝试调用从构造函数中调用虚拟方法并查看结果时,请始终记住不要在构造函数中调用虚拟方法:),然后忘记C++/CLI中不适用的规则!