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

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

二、继承与构造函数

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

 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. CKPlayer的列表框的demo

    <!DOCTYPE html><html><head> <meta http-equiv="Content-Type" content=& ...

  2. python学习笔记(五岁以下儿童)深深浅浅的副本复印件,文件和文件夹

    python学习笔记(五岁以下儿童) 深拷贝-浅拷贝 浅拷贝就是对引用的拷贝(仅仅拷贝父对象) 深拷贝就是对对象的资源拷贝 普通的复制,仅仅是添加了一个指向同一个地址空间的"标签" ...

  3. JavaEE——Intellij Idea 创建JavaWeb项目

    原文:JavaEE--Intellij Idea 创建JavaWeb项目 折腾Tomcat折腾了两个晚上,第一个晚上怎么都进不了Tomcat的首页,第二个晚上进去了,但是新建的Web项目,在浏览器中运 ...

  4. API接口开发简述示例

    作为最流行的服务端语言PHP(PHP: Hypertext Preprocessor),在开发API方面,是很简单且极具优势的.API(Application Programming Interfac ...

  5. Bootstrap的栅格系统

    Bootstrap的栅格系统 上一节:ASP.NET MVC5 + EF6 入门教程 (6) View中的Razor使用 源码下载:点我下载 要做一个完整的系统,除了需要MVC这样的B/S框架及EF这 ...

  6. 机器学习学习-Types of learning

    Types of learning 基于个人理解.于我们在面对一个详细的问题时.可以依据要达到的目标选择合适的机器学习算法来得到想要的结果.比方,推断一封电子邮件是否是垃圾邮件,就要使用分类(clas ...

  7. Mac OSX操作系统安装和配置Zend Server 6教程(1)

    作为web开发人员,应该熟悉掌握各种系统下安装和配置web服务器与站点的技术. 随着越来越多的开发人员选择Zend Server服务器,慧都推出了在Mac OSX系统安装和配置Zend Server ...

  8. Visual Studio 2015 & C#6.0 试用报告,持续更新。

    昨天早上看到了.net开源的消息,我是非常兴奋的,毕竟局限于Windows的.NET经常被人唾弃.VB暂且不提,C#常年被人指责跨平台性不佳,我也是无能为力.即使有Mono等第三方跨平台工程,.NET ...

  9. ASP.NET DataTable的操作大全

    DataTable表示一个与内存有关的数据表,可以使用工具栏里面的控件拖放来创建和使用,也可以在编写程序过程中根据需要独立创建和使用,最常见的情况是作为DataSet的成员使用,在这种情况下就需要用在 ...

  10. 网页头一定要加的代码段(加注版)一行代码解决各种IE兼容问题,IE6,IE7,IE8,IE9,IE10

      网页头部常见的一段代码 <!--[if lt IE 7 ]><html class="ie6"><![endif]--> <!--[i ...