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

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

二、继承与构造函数

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

 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. CSS3字体模块

    介绍 字体提供了包含字符的视觉表现的资源.在最简单的等级中,其包含由字符编码到表示这些字符的形状(被称为字形)的映射信息.根据一组标准字体属性被分入一个字体家族的字体共享一个通用设计风格.在一个家族中 ...

  2. Codeforces Round #FF 446A DZY Loves Sequences

    预处理出每一个数字能够向后延伸多少,然后尝试将两段拼起来. C. DZY Loves Sequences time limit per test 1 second memory limit per t ...

  3. jquery+html三级联动下拉框及详情页面加载时的select初始化问题

    html写的三个下拉框,如下: <select name="ddlQYWZYJ" id="ddl_QYWZYJ" class="fieldsel ...

  4. 异步提交form的时候利用jQuery validate实现表单验证

    异步提交form的时候利用jQuery validate实现表单验证相信很多人都用过jquery validate插件,非常好用,并且可以通过下面的语句来自定义验证规则    // 电话号码验证    ...

  5. leetcode[71] Sqrt(x)

    题目,就是实现一个开方,返回是整数.int sqrt(int x) 用二分法,因为一个数的开方肯定小于 x/2 + 1, 因为小于5的某些数的开方并不一定比x/2小,所以要+1,那么们定义一个left ...

  6. android application简要类(一)

    每次应用程序执行.应用application保持实例化的阶级地位.推而广之applicaiton类别,能够完成以下3长期工作: 1.至android应用级事件,如广播的实现中低声回应. 2.传递应用程 ...

  7. JS判断鼠标向上滚动还是向下滚动

    js如何判断滚轮的上下滚动,我们应该都见到过这种效果,用鼠标滚轮实现某个表单内的数字向上滚动就增加,向下滚动就减少的操作,这种效果是通过js对鼠标滚轮的事件监听来实现的.今天简单的研究了一下如何使用j ...

  8. Mysql高级之游标

    原文:Mysql高级之游标 什么是游标?select 语句也许一次性会取出来n条语句,那么游标便可以一次取出来select中的一条记录.每取出来一条,便向下移动一次!可以实现很复杂逻辑! 上面还有有一 ...

  9. Linux 安装配置maven3.0 以及搭建nexus私服

    http://carvin.iteye.com/blog/785365 一.软件准备 1.apache-maven-3.0-bin.tar.gz 下载地址:http://www.apache.org/ ...

  10. des和Rijndael加密

    ------------IV的作用: 为了保证数据的安全,.NET基类库中提供的私钥算法类使用称作密码块链(CBC,Cipher Block Chaining)的链模式,算法使用一个密钥和一个初始化向 ...