调用超类构造函数的规则是什么?

从子类调用超类构造函数的C ++规则是什么?

例如,我知道在Java中,您必须将其作为子类构造函数的第一行(如果您不这样做,则假定隐式调用no-arg超级构造函数 - 如果缺少它,会给您一个编译错误) 。


如果没有参数,基类构造函数会自动调用。 如果要使用参数调用超类构造函数,则必须使用子类的构造函数初始化列表。 与Java不同,C ++支持多重继承(无论好坏),所以基类必须按名称引用,而不是“super()”。

class SuperClass
{
    public:

        SuperClass(int foo)
        {
            // do something with foo
        }
};

class SubClass : public SuperClass
{
    public:

        SubClass(int foo, int bar)
        : SuperClass(foo)    // Call the superclass constructor in the subclass' initialization list.
        {
            // do something with bar
        }
};

关于这里和这里的构造函数初始化列表的更多信息。


在C ++中,所有超类和成员变量的无参构造函数都会在进入构造函数之前调用。 如果你想传递它们的参数,这个叫做“构造函数链接”的单独语法如下所示:

class Sub : public Base
{
  Sub(int x, int y)
  : Base(x), member(y)
  {
  }
  Type member;
};

如果此时运行的任何内容抛出,先前完成构建的基础/成员将调用它的析构函数,并将异常重新抛出给调用者。 如果要在链接期间捕获异常,则必须使用函数try块:

class Sub : public Base
{
  Sub(int x, int y)
  try : Base(x), member(y)
  {
    // function body goes here
  } catch(const ExceptionType &e) {
    throw kaboom();
  }
  Type member;
};

在这种形式下,请注意try块函数的主体,而不是在函数体内; 这允许它捕获由隐式或显式成员和基类初始化引发的异常,以及在函数的主体期间。 但是,如果函数catch块不会引发其他异常,则运行时将重新抛出原始错误; 初始化期间的异常不能被忽略。


在C ++中,有一个构造函数初始化列表的概念,您可以并且应该调用基类的构造函数,并且还应该初始化数据成员。 初始化列表出现在冒号后面的构造函数签名之后,并且位于构造函数的主体之前。 假设我们有一个A类:


class A : public B
{
public:
  A(int a, int b, int c);
private:
  int b_, c_;
};

然后,假设B有一个接受int的构造函数,A的构造函数可能如下所示:


A::A(int a, int b, int c) 
  : B(a), b_(b), c_(c) // initialization list
{
  // do something
}

如您所见,基类的构造函数在初始化列表中调用。 顺便说一句,初始化初始化列表中的数据成员优于为构造函数的body中的b_和c_赋值,因为这样可以节省额外的赋值成本。

请记住,数据成员总是按照它们在类定义中声明的顺序进行初始化,而不管它们在初始化列表中的顺序如何。 为了避免在数据成员彼此依赖时可能出现的奇怪错误,您应该始终确保成员顺序在初始化列表和类定义中相同。 基于同样的原因,基类构造函数必须是初始化列表中的第一项。 如果完全忽略它,那么将自动调用基类的默认构造函数。 在这种情况下,如果基类没有默认构造函数,那么将会出现编译器错误。

链接地址: http://www.djcxy.com/p/18009.html

上一篇: What are the rules for calling the superclass constructor?

下一篇: Setter methods or constructors