有趣的 C++ 抽象函数

发布于 2024-07-09 13:45:44 字数 386 浏览 4 评论 0原文

为什么会发生这种情况?

当你在c++中创建抽象类时:Class A(它有一个纯虚函数) 之后类B继承自类A

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

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

why this is happen ?

When u create abstract class in c++ Ex: Class A (which has a pure virtual function)
after that class B is inherited from class A

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.......?

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 .

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

难理解 2024-07-16 13:45:44

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

当 A 的构造函数仍在运行时,正在构造的对象还不是真正的 A 类型。它仍在构造中。 当构造函数完成后,它现在是一个 A。

派生的 B 也是如此。A 的构造函数首先运行。 现在它是 A。然后 B 的构造函数开始运行。 在此期间,该对象实际上仍然是 A。只有当 B 的构造函数完成时,它才会变成 B。

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

由于纯虚函数,编译器将不允许您生成构造 A 的代码。 但它会生成代码来构造 A,作为构造 B 过程的一部分。这并不涉及任何魔法。 不能构造 A 的规则是由语言规则强加的,而不是由物理学强加的。 语言在构造 B 对象的特殊情况下解除了这一规则。

Quick answer: constructors are special.

When the constructor of A is still running, then the object being constructed is not yet truly of type A. It's still being constructed. When the constructor finishes, it's now an A.

It's the same for the derived B. The constructor for A runs first. Now it's an A. Then the constructor for B starts running. During this, the object is still really an A. Only when B's constructor finishes does it become a B.

You can verify this by trying to call the pure virtual function from the constructors. If the function is defined in A, and B's constructor calls it, there will be a runtime error instead of running B's override, because the object is not of type B yet.

The compiler will not allow you to generate code that will construct an A, due to the pure virtual function. But it will generate code to construct an A as part of the process of constructing a B. There's no magic involved in this. The rule that you cannot construct an A is imposed by the language rules, not by physics. The language lifts that rule under the special circumstance of constructing objects of B.

我不在是我 2024-07-16 13:45:44

类 A 是抽象的,但 类 B 不是。 为了构造类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;
};

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       |
+---------+

class A is abstract but class B is not. In order to construct class B, it must implement all the pure virtual member functions of 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;
};

The A class layout could be something like this:

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

The B class layout could be something like this:

+---------+     +---------+
| vftable | --> | ~B()    | --> address of B::~B()
+---------+     +---------+
| i       |     | foo()   | --> address of B::foo()
+---------+     +---------+
| j       |
+---------+
夕色琉璃 2024-07-16 13:45:44
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() {..}
};
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() {..}
};
霞映澄塘 2024-07-16 13:45:44
 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 类的所有信息。

 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.......?

Actually you have it the wrong way around:

When you create an object of class B the constructor of B is called.
If you do not specify how the B constructor calls A constructor then the compiler will automatically insert as the first action in the initializer list a call to the default constructor of A.

If you do not want to use the default constructor you must explicitly put the call to the appropriate A constructor as the first element in the initializer list.

When the construction of A is complete the construction of B will continue.

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 .

You word the above as if you consider A and B different things. An object of class B is also an object of class A. It is the object as a whole that is valid. The whole object is of class B but this contains (as part of the same object) all the information that was from class A.

末骤雨初歇 2024-07-16 13:45:44

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

A a;
new A();

类之所以抽象是因为它具有纯虚方法。 不过,没有什么本质上可以阻止此类的实例化。 C++ 标准只是说这是不允许的。 编译器完全能够生成实例化抽象类的指令。 它所要做的就是保留适量的内存,然后调用构造函数,就像非抽象类一样。

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

Just because you can't instantiate class A directly doesn't mean it's impossible to instantiate class A. You're not allowed to instantiate A because the compiler knows that A is abstract and rejects any code you write that attempts to directly instantiate A. It forbids code like this:

A a;
new A();

What makes a class abstract is that it has pure virtual methods. There is nothing inherently preventing such a class from being instantiated, though. The C++ standard simply says it's not allowed. The compiler is perfectly capable of generating instructions to instantiate an abstract class. All it has to do is reserve the right amount of memory and then invoke the constructor, the same as it would for a non-abstract class.

When you instantiate B, all the memory for the class gets allocated at once. Since all the bytes are there, there is essentially an A instance there, ready to be initialized by the constructor. (But note that the memory isn't formally considered an object of type A until after the A constructor has finished running.) The A constructor runs, and then the B constructor runs.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文