用C++解释空白类函数

Explain blank class functions in C++

本文关键字:类函数 空白 解释 C++      更新时间:2023-10-16
class forums : public master{
public:
    forums() : next(0),prev(0) {}
}
  1. 请解释一下 next(0( 和 prev(0( 函数到底是什么意思?

  2. 用逗号 (,( 分隔函数表示什么?这些函数旁边的空大括号 {} 有什么效果?

  3. 我是C++的初学者,并试图弄清楚这意味着什么,或者这些写作方式的预期用途?

比如它是专门为覆盖而设计的吗?

你有一个"初始化列表"。

该代码正在设置类实例的nextprev成员的初始值。

如果 nextprev 是类的实例,则该代码可能会调用构造函数,或者如果它们是基元类型,则可能只为它们赋值。

它们是逗号分隔的,因为这就是初始化列表的语法的外观。

空大括号表示 forums 构造函数的主体 - 在此示例中,构造函数本身没有任何变化,因为工作是在初始化列表中完成的。

1(它初始化下一个和上一个到0,就像初始化一样,而不是赋值。

2( 这称为构造函数初始值设定项列表。如果没有它,您需要在构造函数主体中将 next & prev 分配给 0。那不是一回事。您需要了解对象初始化和赋值之间的区别。对于某些类型、引用和 const 对象,初始值设定项列表是必需的。对于复杂对象,最好使用初始值设定项列表,因为在构造函数主体中分配对象时,您将为对象的初始化及其分配付费。对于简单的整型类型,没有区别,但对于具有构造函数的类型,有区别,因为通常,赋值几乎和初始化一样昂贵。

在这里,主体是空的,因为只有下一个和上一个需要初始化,不需要做任何其他事情。

此外,成员初始化顺序非常严格,它按照其声明的顺序发生。您在初始值设定项列表中写下的顺序无关紧要,它发生在声明顺序中。

非常重要,请了解初始化和分配之间的内容。

还要了解声明与定义。如果您不理解这些概念,就会产生很多困惑。

3(这是基本的对象构造。有一个空的身体,因为必须有一个身体;它什么都不做。

简答

这是一个具有空主体的构造函数,以及一个成员初始化列表,该列表将两个数据成员初始化为值 0

  • class-name([ ctor-args ]) [ : member-init-list ] { [ ctor-body ] }

  • member-init-list在哪里member-name(args) [, member-name(args) [, ... ] ].

(注意:不是实际的C++词汇语法结构(


长答案

背景

采用以下类定义:

struct Base {};
struct Derived : Base {};

您可能已经意识到Derived源自Base

您可能已经知道,DerivedBase 都有一个合成(隐式声明(默认(不带参数(构造函数。 Derived 的构造函数隐式/自动调用Base

现在让我们添加一个基本成员函数:

struct Derived : Base {
   void foo() {}
};

我已经声明定义了这个成员函数foo;它的主体是空的,所以当你调用它时什么都不会发生。这是毫无意义的,但它是完全有效的。

现在,让我们创建自己的构造函数:

struct Derived : Base {
   Derived() {}
};

这看起来更熟悉。它仍然是一个具有空体的 [特殊] 函数,并且 Base 构造函数仍在隐式调用。我们没有改变这一点。


处理数据成员

让我们添加一些数据成员并在构造函数中设置它们的值:

struct Derived : Base {
   Derived() {
      x = 0;
      y = 0;
   }
   int x, y;
};

xy都将具有对象构造后0的值。这仍然是根本C++。

但您可能不知道的是,您没有初始化这些数据成员。您只是在可以初始化它们之后分配给它们。

事实上,内置类型的数据成员不是隐式初始化的,所以让我们选择一个更好的例子:

struct Derived : Base {
   Derived() /* HERE */ {
      x = "";
      y = "";
   }
   std::string x, y;
};

xy 在构造函数主体中的代码运行之前隐式初始化。当构造函数主体开始运行时,将初始化的所有成员都已初始化,并且已隐式调用基构造函数。

我们可以截获这种行为并提供我们自己的初始化值,方法是在我上一个代码片段中编写/* HERE */的位置编写成员初始化器列表。使用成员初始化器列表,代码段如下所示:

struct Derived : Base {
   Derived() : x(""), y("") {
      x = "";
      y = "";
   }
   std::string x, y;
};

哇!BKV现在我们将字符串初始化为 ""然后在构造函数主体中为它们分配相同的空值。我们可以摆脱这些任务,然后:

struct Derived : Base {
   Derived() : x(""), y("") {}
   std::string x, y;
};

现在构造函数主体是空的,但构造函数仍然执行操作。它隐式调用基构造函数,并显式初始化数据成员xy为空字符串。

而且,由于std::string有一个执行相同操作的默认构造函数,因此我们可以简短地编写:

struct Derived : Base {
   Derived() : x(), y() {}
   std::string x, y;
};

回到原始示例,这同样适用于内置类型的对象。让我们考虑两个要点:

struct Derived : Base {
   Derived() : next(0), prev(0) {}
   Derived* next;
   Derived* prev;
};

处理基类

而且,作为额外的好处,我们可以使用成员初始化列表来显式调用基构造函数:

struct Derived : Base {
   Derived() : Base(), next(0), prev(0) {}
   Derived* next;
   Derived* prev;
};

除非基构造函数想要一些参数,否则这是毫无意义的:

struct Base {
   Base(int x) {}
};
struct Derived : Base {
   Derived() : Base(0), next(0), prev(0) {}
   Derived* next;
   Derived* prev;
};

我希望这是有用的。

请参阅 ">

C++ 中的初始化列表

">

这不是一个函数。它具有与以下功能相同的功能:

forums()
{
    next = 0;
    prev = 0;
}

Next 和 Prev 可能是基类的成员。

但是存在差异 - 首先,使用初始化列表比事后为成员分配值更快。