百度网站打开,linux wordpress路径,wordpress 订阅到,直播的网站开发当写继承类的时候#xff0c;需要清楚父类与子类之间的交互。像生成顺序#xff0c;构造函数链#xff0c;以及转化都可以是问题的根源。
1、父类构造函数 对象不会马上就能干活#xff1b;它们必须由父类以及所包含的任意对象进行构建。c定义了如下的生成顺序#xff1a… 当写继承类的时候需要清楚父类与子类之间的交互。像生成顺序构造函数链以及转化都可以是问题的根源。
1、父类构造函数 对象不会马上就能干活它们必须由父类以及所包含的任意对象进行构建。c定义了如下的生成顺序
、如果类有基类基类的缺省构造函数先执行除非在构造函数生成器中有对基类的调用在这种情况下生成器先调用而不是缺省构造函数。、类的Non-static数据成员以它们声明的顺序构建。、类的构造函数体执行。 这些规则可以递归应用。如果类有一个祖父类祖父类先于父类初始化等等。下面的代码展示了这种生成次序。该代码正确执行的输出为123。
import std;using namespace std;class Something
{
public:Something() { print(2); }
};class Base
{
public:Base() { print(1); }
};class Derived : public Base
{
public:Derived() { print(3); }private:Something m_dataMember;
};int main()
{Derived myDerived;
} 当myDerived对象生成的时候Base的构造函数先调用输出字符串“1”。接下来m_dataMember初始化调用Something构造函数它输出字符串“2”。最后Derived构造函数调用输出“3”。 注意Base的构造函数是自动调用的。c自动调用父类有的缺省构造函数。如果父类没有缺省构造函数或者有但是你想用另外的父类构造函数你可以在构造函数初始化器内初始化数据成员时chain构造函数。例如下面的代码展示了Base的缺省缺省构造函数的版本。Derived的相关版本必须显式告诉编译器如何 调用Base构造函数要么代码就会编译失败。
class Base
{
public:explicit Base(int i) {}
};class Derived : public Base
{
public:Derived() : Base { 7 } { /* Other Deriveds initialization ... */ }
}; Derived构造函数传了一个固定值7给Base构造函数。当然了Derived也可以传递一个变量
Derived::Derived(int i) : Base { i } { /* Other Deriveds initialization ... */ } 从继承类中传递构造函数变量给基类是完全没有问题的也是很正常的。然则传递数据成员是不行的。代码编译没有问题但是记住数据成员是在基类构建完成之后才会初始化的。如果作为参数传递一个数据成员给父类构造函数它是没有被初始化的。
2、父类析构函数 因为析构函数不接受参数编程语言会自动调用父类的析构函数。析构函数的调用次序与构造函数的次序刚好相反
、调用类的析构函数体。、类的数据成员以构建相反的次序依次失效。、如果有父类的话被析构。 再次声明该规则可以递归。链条最低的成员首先失效。下面的代码给上面的例子添加了析构函数。析构函数都声明成了virtual!执行的话代码输出“123321”。
class Something
{
public:Something() { print(2); }virtual ~Something() { print(2); }
};class Base
{
public:Base() { print(1); }virtual ~Base() { print(1); }
};class Derived : public Base
{
public:Derived() { print(3); }virtual ~Derived() override { print(3); }private:Something m_dataMember;
}; 如果上面的析构函数不是被声明为virtual代码看起来也能正常运行。然而如果 调用Base指针上的delete而该指针是指向一个Derived实例的话析构链条就不对了。例如如果将上面代码的所有析构函数的virtual与override关键字移除的话当Derived对象作为一个指向Base的对象来访问并且删除的话就会有问题出现了如下所示
Base* ptr { new Derived{} };
delete ptr; 该代码的输出会是令人吃惊的“1231”。当ptr指针删除时只有Base析构函数被调用因为该析构函数没有被声明为virtual。作为结果Derived析构函数没有被调用其数据成员的析构函数也没有被调用 从技术上来说改正前面的问题只需要将Base的析构函数标记为virtual。其”virtualness”属性自动应用于任何它的继承类。然而我强烈建议你显式将所有的析构函数标记为virtual这样就永远不需要担心这方面的问题。 警告总是把析构函数标记为virtual!编译器生成的缺省析构函数不是virtual所以应该定义或显式缺省一个virtual析构函数至少对于所有的non-final基类。
3、在构造函数也析构函数中调用virtual成员函数 在构造函数与析构函数中virtual成员函数表现是不一样的。如果继承类一从基类重载来的virtual成员函数从基类构造函数或析构函数调用该成员函数调用的是基类的virtual成员函数而不是继承类中的重载版本换名话说在构造函数或析构函数中对virtual成员函数的调用是在编译时静态解析的。 构造函数的这种行为的原因与构建一个继承类的实例时的初始化顺序相关。当生成这样的实例时任何基类的构造函数先调用在继承类实例整体初始化之前。因此去调用还没有初始化的继承类中重载的virtual成员函数是危险的。对于析构函数也是类似的原因也是当析构一个对象时其析构的顺序。 如果确实需要对构造函数进行行为多态化虽然不是很推荐也是可以在基类中定义一个initialize() virtual成员函数的它可以被继承类重载。客户生成类实例在构建完成后一定要调用这个initialize()成员函数。 同样的如果需要在析构函数中使行为多态化再次强调是不推荐的可以定义一个shutdown() virtual成员函数对象在析构之前需要客户去调用这个函数。