一、不能自动继承的成员函数

构造函数
析构函数
=运算符

二、继承与构造函数

基类的构造函数不被继承,派生类中需要声明自己的构造函数。
声明构造函数时,只需要对本类中新增成员进行初始化,对继承来的基类成员的初始化(调用基类构造函数完成)。
派生类的构造函数需要给基类的构造函数传递参数

 C++ Code 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

 
#include <iostream>


using 
namespace std;

class ObjectB

{


public:

    ObjectB(
int objb) : objb_(objb)

    {

        cout << 
"ObjectB ..." << endl;

    }

    ~ObjectB()

    {

        cout << 
"~ObjectB ..." << endl;

    }

    
int objb_;

};

class ObjectD

{


public:

    ObjectD(
int objd) : objd_(objd)

    {

        cout << 
"ObjectD ..." << endl;

    }

    ~ObjectD()

    {

        cout << 
"~ObjectD ..." << endl;

    }

    
int objd_;

};

class Base

{


public:

    Base(
int b) : b_(b), objb_(
)

    {

        cout << 
"Base ..." << endl;

    }

    Base(
const Base &other) : objb_(other.objb_), b_(other.b_)

    {

}

    ~Base()

    {

        cout << 
"~Base ..." << endl;

    }

    
int b_;

    ObjectB objb_;

};

class Derived : 
public Base

{


public:

    Derived(
int b, 
int d) : d_(d), Base(b), objd_(
)

    {

        cout << 
"Derived ..." << endl;

    }

    Derived(
const Derived &other) : d_(other.d_), objd_(other.objd_), Base(other)

    {

}

    ~Derived()

    {

        cout << 
"~Derived ..." << endl;

    }

    
int d_;

    ObjectD objd_;

};

int main(
void)

{

    Derived d(

);

    cout << d.b_ << 
" " << d.d_ << endl;

Base b1(
);

    Base b2(b1);

    cout << b2.b_ << endl;

Derived d2(d);

    
return 
;

}

从输出可以看出:

派生类对象的构造次序:

先调用基类对象成员的构造函数,接着是基类的构造函数,然后是派生类的对象成员的构造函数,最后是派生类自身的构造函数。

也可以这样来看:构造函数执行的顺序是先执行初始化列表,然后是函数体。初始化列表参数多个且其中有调用基类构造函数时,先执行基类构造函数(从最远的开始,如果多重继承则按继承的顺序);其他对象成员若不止一个,则按定义的顺序构造,与初始化列表顺序无关。关于初始化列表可以参考这里

析构的顺序与构造的顺序相反。

三、友元关系、静态成员与继承

友元关系不能被继承

静态成员无所谓继承

 C++ Code 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

 
#include <iostream>


using 
namespace std;

class Base

{


public:

    
static 
int b_;

};

int Base::b_ = 
;


class Derived : 
public Base

{

};

int main(
void)

{

    Base b;

    Derived d;

    cout << Base::b_ << endl;

    cout << b.b_ << endl;

cout << Derived::b_ << endl;

    cout << d.b_ << endl;

return 
;

}

都能访问,输出100,但推荐使用类::xx 访问,如b.b_ 访问存在歧义,实际上static成员不属于任一对象。

四、派生类到基类的转换

当派生类以public方式继承基类时,编译器可自动执行的转换(向上转型 upcasting 安全转换)

派生类对象指针自动转化为基类对象指针

派生类对象引用自动转化为基类对象引用

派生类对象自动转换为基类对象(特有的成员消失)

当派生类以private/protected方式继承基类时

派生类对象指针(引用)转化为基类对象指针(引用)需用强制类型转化。但不能用static_cast,要用reinterpret_cast

不能把派生类对象强制转换为基类对象

 C++ Code 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

 
#include <iostream>


#include <string>


using 
namespace std;

class Employee

{


public:

    Employee(
const string &name, 
const 
int age, 
const 
int deptno) : name_(name),

        age_(age), deptno_(deptno)

    {

}


private:

    string name_;

    
int age_;

    
int deptno_;

};

class Manager : 
public Employee

{


public:

    Manager(
const string &name, 
const 
int age, 
const 
int deptno, 
int level)

        : Employee(name, age, deptno), level_(level)

    {

}


private:

    
int level_;

};

class Manager2 : 
private Employee

{


public:

    Manager2(
const string &name, 
const 
int age, 
const 
int deptno, 
int level)

        : Employee(name, age, deptno), level_(level)

    {

}


private:

    
int level_;

};

int main(
void)

{

    Employee e1(
"zhangsan", 

);

    Manager m1(
"lisi", 


);

    Manager2 m2(
"wangwu", 


);

    Employee *pe;

    Manager *pm;

    Manager2 *pm2;

pe = &e1;

    pm = &m1;

    pm2 = &m2;

pe = &m1;   
// 派生类对象指针可以转化为基类对象指针。将派生类对象看成基类对象
    
//pm = &e1; // 基类对象指针无法转化为派生类对象指针。无法将基类对象看成是派生类对象

e1 = m1;    
// 派生类对象可以转化为基类对象。将派生类对象看成基类对象
    
// 会产生对象切割(派生类特有成员消失)。object slicing

//pe = pm2; //私有或保护继承的时候,派生类对象指针不可以自动转化为基类对象指针
    pe = 
reinterpret_cast<Employee *>(pm2);

//e1 = m2;  // 私有或保护继承的时候,派生类对象无法转化为基类对象。
    
//e1 = reinterpret_cast<Employee>(m2); // 私有或保护继承的时候,派生类对象无法强制转化为基类对象。

pm = 
static_cast<Manager *>(pe);    
// 基类指针可以强制转化为派生类指针,但是不安全

//m1 = reinterpret_cast<Manager>e1; // 基类对象无法强制转化为派生类对象

return 
;

}

五、基类到派生类的转换

基类对象指针(引用)可用强制类型转换为派生类对象指针(引用), 而基类对象无法执行这类转换.
向下转型不安全,没有自动转换的机制

// 从语法上来演示基类对象可以转化为派生类对象,但是没有意义

1、转换构造函数:
Manager(const Employee& other) : Employee(other), level_(-1)
{

}

2、类型转换运算符:

Employee::operator Manager()
{

return Manager(name_, age_, deptno_, -1);

}

参考:

C++ primer 第四版
Effective C++ 3rd
C++编程规范

从零开始学C++之继承(二):继承与构造函数、派生类到基类的转换的更多相关文章

  1. C# 派生和继承(派生类与基类)

    using System; using System.Collections.Generic; using System.Text; namespace 继承 { class Program { st ...

  2. C++类继承--构造函数时先构造基类

    以下说明继承类函数构造时,先构造基类: 析构基类时,若没加上virtual,只析构基类,不析构派生类: 析构派生类时,同时会析构基类: 1. 基类析构函数有virtual #include <s ...

  3. PythonI/O进阶学习笔记_4.自定义序列类(序列基类继承关系/可切片对象/推导式)

    前言: 本文代码基于python3 Content: 1.python中的序列类分类 2. python序列中abc基类继承关系 3. 由list的extend等方法来看序列类的一些特定方法 4. l ...

  4. 【Unity3D基础教程】给初学者看的Unity教程(二):所有脚本组件的基类 -- MonoBehaviour的前世今生

    作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 引子 上一次我们讲了GameObject,C ...

  5. UI(UGUI)框架(二)-------------UIManager单例模式与开发BasePanel面板基类/UIManage统一管理UI面板的实例化/开发字典扩展类

    UIManage单实例: /// 单例模式的核心 /// 1,定义一个静态的对象 在外界访问 在内部构造 /// 2,构造方法私有化 private static UIManager _instanc ...

  6. 从零开始学Electron笔记(二)

    在之前的文章我们简单介绍了一下Electron可以用WEB语言开发桌面级应用,接下来我们继续说一下Electron的菜单创建和事件绑定. 我们接上一章的代码继续编写,上一章代码 https://www ...

  7. 从零开始学ios开发(二):Hello World!来啦!

    今天看了书的第二章,主要介绍了一下Xcode的使用方法和一些必要的说明,最后做了一个“Hello World!”的小程序,其实就是在屏幕上用一个Label显示“Hello World!”,一行代码都没 ...

  8. 从零开始学ios开发(二十):Application Settings and User Defaults(下)

    在上一篇的学习中,我们知道了如何为一个App添加它的Settings设置项,在Settings设置项中我们可以添加哪些类型的控件,这些控件都是通过一个plist来进行管理的,我们只需对plist进行修 ...

  9. 从零开始学安全(四十二)●利用Wireshark分析ARP协议数据包

    wireshark:是一个网络封包分析软件.网络封包分析软件的功能是撷取网络封包,并尽可能显示出最为详细的网络封包资料.Wireshark使用WinPCAP作为接口,直接与网卡进行数据报文交换,是目前 ...

随机推荐

  1. Asp.net vNext 学习3

    Asp.net vNext 学习之路(三) asp.net vNext 对于构建asp.net 程序带来了一些重大的改变,让我们开发asp.net 程序的时候更加的方便和高效. 1,可以很容易的去管理 ...

  2. 浅谈移动Web开发(上):深入概念

    PPI 什么是PPI PPI的复杂之处在于如果他所属的上下文环境不同,意义也会完全不一样. 当我们在谈论显示设备的PPI时,它代指的屏幕的像素密度:当我们在谈论和图片相关时,我们谈论的是打印时的分辨率 ...

  3. SOA面向服务架构

    SOA面向服务架构 风尘浪子 只要肯努力,梦想总有一天会实现 随笔分类 - SOA面向服务架构 结合领域驱动设计的SOA分布式软件架构 摘要: 领域驱动设计DDD的总体结构,Repository层使用 ...

  4. Django查询的琐碎记录

    我的需求是这样的,获取指定用户的获“赞”总数. 用户 models.py class UserProfile(models.Model): user = models.OneToOneField(Us ...

  5. jQuery数字加减插件

    jQuery数字加减插件 我们在网上购物提交订单时,在网页上一般会有一个选择数量的控件,要求买家选择购买商品的件数,开发者会把该控件做成可以通过点击实现加减等微调操作,当然也可以直接输入数字件数.本文 ...

  6. linux 线程回顾

    额,时隔两年重新写博客了. 这次看一下thread_cond_wait(pthread_cond_t * cond, pthread_mutex_t *mutex)和thread_cond_signa ...

  7. 图解:SQL Server SSIS包和job的部署攻略

    原文:图解:SQL Server SSIS包和job的部署攻略 以下将建立一个SQL Server SSIS包 然后在job中使用这个包,并将job部署到目标机器 1. 首先建立ssis包,使用sql ...

  8. 程序猿必要10免费的钱jquery小工具

    本周带来10款免费的jquery插件.假设你也有好的作品,欢迎分享到社区中来,在得到帮助的同一时候,也能与很多其它人分享来自你的作品. jQuery导航菜单置顶插件 - stickyUp . 在线演示 ...

  9. css 初始化

    html,body,h1,h2,h3,h4,h5,h6,div,dl,dt,dd,ul,ol,li,p,blockquote,pre,hr,figure,table,caption,th,td,for ...

  10. Web应用和RESTful架构

    Web应用和RESTful架构 单页Web应用 概述 单页Web应用并不是突然诞生的一门新技术,而是web展示的一种新的尝试.它将所有的动作局限于一个Web页面,在加载站点首页的时候就加载站点需要的J ...