调用超类构造函数的规则是什么?
从子类调用超类构造函数的C ++规则是什么?
例如,我知道在Java中,你必须做它作为子类构造函数的第一行(如果你不这样做,假设隐式调用一个无参的超级构造函数 – 如果缺less的话会给你一个编译错误) 。
如果没有参数,基类构造函数会自动调用。 如果要使用参数调用超类构造函数,则必须使用子类的构造函数初始化列表。 与Java不同的是,C ++支持多重inheritance(好或坏),所以基类必须按名称来引用,而不是“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 ++中,所有超类和成员variables的无参构造函数在进入构造函数之前都会被调用。 如果你想传递它们的参数,这个被称为“构造函数链接”的单独的语法如下所示:
class Sub : public Base { Sub(int x, int y) : Base(x), member(y) { } Type member; };
如果现在运行的任何东西都抛出,那么之前完成构build的基础/成员就会调用它的析构函数,并将exception重新抛出给调用者。 如果要在链接期间捕获exception,则必须使用函数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; };
在这种forms下,请注意try块是函数的主体,而不是在函数体内; 这允许它捕获由隐式或显式成员和基类初始化引发的exception,以及在函数的主体期间。 但是,如果一个函数catch块没有抛出一个不同的exception,运行时会重新抛出原来的错误; 初始化期间的exception不能被忽略。
在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 }
正如你所看到的,基类的构造函数在初始化列表中被调用。 顺便说一句,初始化初始化列表中的数据成员最好是在构造函数的主体中为b_和c_赋值,因为这样可以节省额外的赋值成本。
请记住,数据成员总是按照它们在类定义中声明的顺序进行初始化,而不pipe它们在初始化列表中的顺序如何。 为了避免在数据成员彼此依赖时可能出现的奇怪的错误,您应该始终确保成员顺序在初始化列表和类定义中相同。 基于同样的原因,基类构造函数必须是初始化列表中的第一项。 如果完全忽略它,那么基类的默认构造函数将被自动调用。 在这种情况下,如果基类没有默认构造函数,将会出现编译错误。
将值传递给父构造函数的唯一方法是通过初始化列表。 初始化列表是用一个:然后一个类的列表和要传递给这个类构造函数的值来实现的。
Class2::Class2(string id) : Class1(id) { .... }
还要记住,如果你有一个父类没有参数的构造函数,它将在子构造函数执行之前被自动调用。
如果你有一个没有参数的构造函数,它将在派生类构造函数执行之前被调用。
如果你想用参数调用一个基本的构造函数,你必须在派生的构造函数中显式地写出如下的代码:
class base { public: base (int arg) { } }; class derived : public base { public: derived () : base (number) { } };
不能在C ++中调用父类构造函数的情况下构造派生类。 如果它是一个非参数的C'tor,它会自动发生,如果直接调用派生构造函数如上所示,或者代码不能编译,则会发生这种情况。
每个人都提到了通过初始化列表的构造函数调用,但没有人说可以从派生成员的构造函数的主体中显式调用父类的构造函数。 看到这个问题,例如, 从一个子类的构造函数体中调用一个基类的构造函数 。 重点是,如果您在派生类的主体中使用对父类或超类构造函数的显式调用,实际上只是创build父类的实例,而不是在派生对象上调用父类构造函数。 在派生类对象上调用父类或超类构造函数的唯一方法是通过初始化列表,而不是在派生类构造函数体中。 所以也许它不应该被称为“超类构造函数调用”。 我把这个答案放在这里,因为有人可能会感到困惑(就像我做的那样)。
如果在基础构造函数中有默认参数,则会自动调用基类。
using namespace std; class Base { public: Base(int a=1) : _a(a) {} protected: int _a; }; class Derived : public Base { public: Derived() {} void printit() { cout << _a << endl; } }; int main() { Derived d; d.printit(); return 0; }
输出是:1
CDerived::CDerived() : CBase(...), iCount(0) //this is the initialisation list. You can initialise member variables here too. (eg iCount := 0) { //construct body }
当一个类从多个类派生时,没有人提到构造函数调用的顺序。 序列如派生类所述。