1.5 派生类构造函数、析构函数......

来源:互联网 发布:体育套利软件 编辑:程序博客网 时间:2024/06/15 01:55

1.5 派生类构造函数、析构函数……

派生类的构造函数

每个类都会继承直接基类的所有成员。对于一个最终的派生类来说,它会继承其直接基类的成员,该直接基类的成员又含有其基类的成员,以此类推直至继承链的顶端。因此,最终的派生类将包含它的直接基类的子对象以及每个间接基类的子对象。

每个类控制它自己的成员初始化过程。

尽管在派生类对象中含有从基类继承而来的成员,但是派生类并不能直接初始化这些成员。和其他创建了基类对象的代码一样,派生类也必须使用基类的构造函数来初始化它的基类部分。派生类对象的基类部分与派生类对象自己的数据成员都是在构造函数的初始化阶段执行初始化操作的。类似于我们初始化成员的过程,派生类构造函数同样是通过构造函数初始化列表来将实参传递给基类构造函数的。

这里写图片描述

除非我们特别指出,否则派生类对象的基类部分会向数据成员一样执行默认初始化。如果想使用其他的基类构造函数,我们需要以类名加圆括号内的实参列表的形式为构造函数提供初始值。这些实际参数将帮助编译器决定到底应该选用哪个构造函数来初始化派生类对象的基类部分。

首先初始化基类的部分,然后按照声明的顺序依次初始化派生类的成员。

#include <iostream>using namespace std;class Base{public:    Base() = default;    Base(int m, int n, int k): b1(m), b2(n), b3(k) {}    int b1;protected:    int b2;private:    int b3;};class Derived: public Base{public:    Derived() = default;    Derived(int a, int b, int c, int d, int e, int f): Base(a, b, c), d1(d), d2(e), d3(f) {}    Derived(int a, int b, int c): d1(a), d2(b), d3(c) {}    int d1;protected:    int d2;private:    int d3;};int main(){    Base base1(1,2,3);    Derived derived1(4,5,6,7,8,9);    Derived derived2(10,11,12);    cout << base1.b1 << endl; //1    cout << derived1.b1 << " " << derived1.d1 << endl; //4 7    cout << derived2.b1 << " " << derived2.d1 << endl; //未定义 10    return 0;}

继承的构造函数

在C++11新标准中,派生类能够重用其直接基类定义的构造函数。尽管如我们所知,这些构造函数并非以常规的方式继承而来,但是为了方便,我们不妨姑且称其为“继承”的。

一个类只初始化它的直接基类,出于同样的原因,一个类也只继承其直接基类的构造函数。

类不能继承默认构造函数、拷贝构造函数、移动构造函数,如果派生类没有直接定义这些构造函数,则编译器将为派生类合成它们。

派生类继承基类构造函数的方式是提供一条注明了(直接)基类名的using声明语句。

通常情况下,using声明语句只是令某个名字在当前作用域内可见。而当作用于构造函数时,using声明语句将令编译器产生代码。

对于基类的每个构造函数,编译器都生成一个与之对应的派生类构造函数。换句话说,对于基类的每个构造函数,编译器都在派生类中生成一个形参列表完全相同的构造函数。

这些编译器生成的构造函数如:

derived(parms) : base(args){}

其中,derived是派生类的名字,base是基类的名字,parms是构造函数的形参列表,args将派生类构造函数的形参传递给基类的构造函数。

如果派生类含有自己的数据成员,则这些成员将被默认初始化。

#include <iostream>using namespace std;class Base{public:    Base() = default;    Base(int m, int n, int k): b1(m), b2(n), b3(k) {}    int b1;protected:    int b2;private:    int b3;};class Derived: public Base{public:    using Base::Base; // 等价于Drived(int a,int b,int c): Base(a,b,c) {}    int d1;protected:    int d2;private:    int d3;};int main(){    Derived derived1(4,5,6);    cout << derived1.b1 << " " << derived1.d1 << endl;//4 未定义    Derived derived; //合成默认构造函数    Derived derived2 = derived1; //合成拷贝构造函数    return 0;}

派生类的析构函数

和构造函数以及赋值运算符不同的是,派生类析构函数只负责销毁由派生类自己分配的资源。

对象销毁的顺序正好与其创建的顺序相反:派生类析构函数首先执行,然后是基类的析构函数,以此类推,沿着继承体系的反方向直至最后。

class D: public Base{  public:        ~D(){} // Base::~Base()被自动调用执行}

派生类的拷贝构造函数

当为派生类定义拷贝构造函数时,我们通常使用基类的拷贝构造构造函数初始化派生类对象的基类部分。

class D: public Base{  public:       //Base(d)一般会匹配Base的拷贝构造函数。       //即,将一个D类型的对象d绑定到Base拷贝构造函数的Base&形参上。       //Base的拷贝构造函数负责将D类型的对象d的基类部分拷贝给要创建的派生类对象的基类部分。       D(const D &d): Base(d), D的成员初始化{派生类拷贝构造函数函数体;}}

在默认情况下,基类默认构造函数初始化派生类对象的基类部分。

如果我们想拷贝基类部分,则必须在派生类的构造函数初始值列表中显式地使用基类的拷贝构造函数。

class D: public Base{  public:        //假设我们没有提供基类的初始值,        //Base的默认构造函数将被用来初始化派生类对象的基类部分。       D(const D &d): D的成员初始化{派生类拷贝构造函数函数体;}}

派生类的拷贝赋值运算符

与拷贝构造函数一样,派生类的赋值运算符必须显示地为派生类对象的基类部分赋值。

 class D: public Base{  public:       D& operator=(const D &rhs)       {         //显式调用基类赋值运算符,令其为派生类对象的基类部分赋值         Base::operator=(rhs);         //为派生类对象自定义的成员赋值       }}

综合示例

#include <iostream>using namespace std;class Base{public:    int a;    int b;    int c;    Base() = default;    Base(int l, int m, int n):a(l), b(m), c(n){}    Base(const Base &object): a(object.a), b(object.b), c(object.c){}    Base& operator=(const Base &object)    {        a = object.a;        b = object.b;        c = object.c;        return *this;    }};class Derived: public Base{public:    int d;    int e;    int f;    Derived() = default;    Derived(int h, int i, int j):d(h), e(i), f(j){}    Derived(int h, int i, int j, int k, int l, int m):Base(h,i,j), d(k), e(l), f(m){}    Derived(const Derived &object): Base(object),d(object.d),e(object.e),f(object.f){}    Derived&operator=(const Derived &object)    {        Base::operator=(object);        d = object.d;        e = object.e;        f = object.f;        return *this;    }};int main(){    Base base;    Base base1(1,2,3);    Derived derived;    Derived derived1(11,12,13);    Derived derived2(21,22,23,24,25,26);    Derived derived3(31,32,33,34,35,36);    derived2 = derived3;    cout << base1.a << base1.b << base1.c << endl;    cout << derived2.a << derived2.b << derived2.c << endl;    cout << derived2.d << derived2.e << derived2.f << endl;}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 两个人住酒店只有一张身份证怎么办 农村社保卡信息错了说改不了怎么办 社保卡与原医保卡信息错误怎么办 学校发的社保卡丢了怎么办 魔棒工具选中选区后再怎么办 微信每次打开都出现月球图案怎么办 仙人掌的刺扎手里弄不出来怎么办 保险交满15年领了一年死了怎么办 狗咬了出了点血怎么办 被小狗咬到了吃了海鲜怎么办 想给一个人道歉又不敢说怎么办 被尘封的故事中魔法师不见了怎么办 宝骏5602挡升3挡有点卡怎么办 剥开的榴莲没熟壳又扔了怎么办 视频播放器激活码设备超限了怎么办 ai如何把右边菜单栏隐藏了怎么办 矫正牙齿粘牙齿的胶掉了怎么办 3m双面胶生产的时候胶不干怎么办 新房赠送面积没地热想接地热怎么办 教育网注册报名的用户名忘了怎么办 艺术生校考通过文化没过本线怎么办 想做主持人 但不是播音专业怎么办 微信登录版本最低登录不上怎么办 所录微课的视频声音小是怎么办 电脑开机黑屏只有光标在闪怎么办 联想家悦重装系统时驱动缺失怎么办 ps做到一半电脑重启了怎么办 宝宝起风疹怎么办 要注意的问题 惠普笔记本刚换的显卡又坏了怎么办 电脑装驱动时不注意点了跳过怎么办 刚抱回来的小猫不吃饭怎么办 三年级小孩字认的太少怎么办 孩子写字手出汗怎么办用什么笔壳 墙壁被小孩用彩色笔画花了怎么办 传图识字里有些字识别不了怎么办 一岁四个月宝宝智力发育迟缓怎么办 小打架受伤对方家长不配合怎么办 宝宝要上幼儿园了家长该怎么办 断奶涨奶怎么办又能防止乳房变形 孩子在幼儿园被小朋友打了怎么办 孩子在幼儿园被小朋友咬了怎么办