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

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

二、继承与构造函数

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

 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. NetMQ

    NetMQ发布订阅C#示例 NetMQ (ZeroMQ to .Net),ØMQ号称史上最快中间件.它对socket通信进行了封装,使得我们不需要写socket函数调用就能完成复杂的网络通信.和一般意 ...

  2. JS对text非空判断,非空校验

    function JTrim(s){    return s.replace(/(^\s*)|(\s*$)/g, "");} //你先调用一下这个方法,然后在判断 function ...

  3. 递归与尾递归(C语言)

    原文:递归与尾递归(C语言)[转] 作者:archimedes 出处:http://www.cnblogs.com/archimedes/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留 ...

  4. Python什么是值或引用函数参数

    这篇文章是Python前往遇到有疑问的功能. 下面一段是原有的基础教程Python函数. 按值传递參数和按引用传递參数 全部參数(自变量)在Python里都是按引用传递.假设你在函数里改动了參数,那么 ...

  5. ZOJ 2109 FatMouse&#39; Trade (背包 dp + 贪婪)

    链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1109 FatMouse prepared M pounds of cat ...

  6. Linux Telnet安装配置

    本文以红帽6.2 64位版本为例,其它linux类似: linux默认是使用SSH服务的 而不安装telnet服务 ,所以需要手动安装telnet. 1.telnet的安装包有两个,分别是: teln ...

  7. Node.js日志框架选型比較:Winston

    日志对于问题定位.调试,系统性能调优至关重要,尤其是系统复杂以及在线执行的情况下. 好的开发框架都会有一个可开启关闭/可配置记录级别的日志系统.我们从下面几个方面来做选型: 1. 每行日志都须要有准确 ...

  8. jquery 部分效果

    $(selector).hide()            隐藏被选元素 $(selector).show()           显示被选元素 $(selector).toggle()        ...

  9. 命令行配置源和安装本地rpm包

    因为Firefox的在写博客时提交代码会丢失缩进,所以打算安装Chrome来写博,还不错,学到了两条命令- [shell] sudo yum-config-manager --add-repo=htt ...

  10. Libcurl最初的实现tfp上传和下载功能

    研究报告指出的目标是使用libcurl实现ftp文件上传和下载功能 一.Libcurlde简要 Libcurl的而且易于使用的利用url进行文件传输的库. , libcurl当前支持DICT, FIL ...