前面我们说基类的成员函数可以被继承,可以通过派生类的对象访问,但这仅仅指的是普通的成员函数,类的构造函数不能被继承。构造函数不能被继承是有道理的,因为即使继承了,它的名字和派生类的名字也不一样,不能成为派生类的构造函数,当然更不能成为普通的成员函数。

在设计派生类时,对继承过来的成员变量的初始化工作也要由派生类的构造函数完成,但是大部分基类都有 private 属性的成员变量,它们在派生类中无法访问,更不能使用派生类的构造函数来初始化。

这种矛盾在C++继承中是普遍存在的,解决这个问题的思路是:在派生类的构造函数中调用基类的构造函数。

#include<iostream>
using namespace std;
//基类People
class People{protected:char *m_name;int m_age;
public:People(char*, int);
};
People::People(char *name, int age): m_name(name), m_age(age){}
//派生类Student
class Student: public People{private:float m_score;
public:Student(char *name, int age, float score);void display();
};
//People(name, age)就是调用基类的构造函数
Student::Student(char *name, int age, float score): People(name, age), m_score(score){ }
void Student::display(){cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<"。"<<endl;
}
int main(){Student stu("小明", 16, 90.5);stu.display();return 0;
}

运行结果为:
小明的年龄是16,成绩是90.5。

请注意第 23 行代码:

Student::Student(char *name, int age, float score): People(name, age), m_score(score){ }

People(name, age)就是调用基类的构造函数,并将 name 和 age 作为实参传递给它,m_score(score)是派生类的参数初始化表,它们之间以逗号,隔开。
也可以将基类构造函数的调用放在参数初始化表后面:

Student::Student(char *name, int age, float score): m_score(score), People(name, age){ }

但是不管它们的顺序如何,派生类构造函数总是先调用基类构造函数再执行其他代码(包括参数初始化表以及函数体中的代码),总体上看和下面的形式类似:

Student::Student(char *name, int age, float score){People(name, age);m_score = score;
}

当然这段代码只是为了方便大家理解,实际上这样写是错误的,因为基类构造函数不会被继承,不能当做普通的成员函数来调用。换句话说,只能将基类构造函数的调用放在函数头部,不能放在函数体中。
另外,函数头部是对基类构造函数的调用,而不是声明,所以括号里的参数是实参,它们不但可以是派生类构造函数参数列表中的参数,还可以是局部变量、常量等,例如:

Student::Student(char *name, int age, float score): People("小明", 16), m_score(score){ }

构造函数的调用顺序
从上面的分析中可以看出,基类构造函数总是被优先调用,这说明创建派生类对象时,会先调用基类构造函数,再调用派生类构造函数,如果继承关系有好几层的话,例如:

A --> B --> C

那么创建 C 类对象时构造函数的执行顺序为:

A类构造函数 --> B类构造函数 --> C类构造函数

构造函数的调用顺序是按照继承的层次自顶向下、从基类再到派生类的。

还有一点要注意,派生类构造函数中只能调用直接基类的构造函数,不能调用间接基类的。以上面的 A、B、C 类为例,C 是最终的派生类,B 就是 C 的直接基类,A 就是 C 的间接基类。

C++ 这样规定是有道理的,因为我们在 C 中调用了 B 的构造函数,B 又调用了 A 的构造函数,相当于 C 间接地(或者说隐式地)调用了 A 的构造函数,如果再在 C 中显式地调用 A 的构造函数,那么 A 的构造函数就被调用了两次,相应地,初始化工作也做了两次,这不仅是多余的,还会浪费CPU时间以及内存,毫无益处,所以 C++ 禁止在 C 中显式地调用 A 的构造函数。

C++基类和派生类的构造函数(一)相关推荐

  1. C++中基类与派生类的构造函数和析构函数

    1.Cpp中的基类与派生类的构造函数 基类的成员函数可以被继承,可以通过派生类的对象访问,但这仅仅指的是普通的成员函数,类的构造函数不能被继承.构造函数不能被继承是有道理的,因为即使继承了,它的名字和 ...

  2. 构造函数怎么在主函数调用_C++ 虚基类及其派生类构造函数(学习笔记:第7章 12)...

    虚基类及其派生类构造函数[1] 建立对象时所指定的类称为最远派生类. 虚基类的成员是由最远派生类的构造函数通过调用虚基类的构造函数进行初始化的. 在整个继承结构中,直接或间接继承虚基类的所有派生类,都 ...

  3. 派生类到基类的转换 和基类到派生类的转换

    一. 基类与派生类的转换     3种继承方式(公用.保护.私有继承)中,公用派生类才是基类真正的子类型,它完整地继承了基类的功能.     不同类型数据之间在一定条件下可以进行类型的转换.基类与派生 ...

  4. C++:基类和派生类

    4.1 派生类的声明 继承实例如下: class Person{ //声明基类Person public:void print(){cout<<"name:"<& ...

  5. 基类与派生类之间的转换关系

    一. 派生类到基类的转换: 1.可以使用派生类指针初始化基类指针,同样也可以使用派生类的引用或对象初始化基类的引用,注意这里提到的是对象的指针和引用而不是对象本身: (但是,在使用基类指针(或引用)指 ...

  6. c++中基类与派生类中隐含的this指针的分析

    先不要看结果,看一下你是否真正了解了this指针? 1 #include<iostream> 2 using namespace std; 3 4 class Parent{ 5 publ ...

  7. C++学习 十五、类继承(1)基类,派生类,访问权限,protected

    C++学习 十五.类继承(1)基类,派生类 前言 类继承 类的关系与继承 基类, 派生类 基类 派生类 构造函数,析构函数 文件位置 访问权限 protected 后记 前言 本篇开始学习C++类的继 ...

  8. python根据一个基类生成派生类_python中的封装继承多态

    1.封装 类的封装可以隐藏类的实现细节,迫使用户只能通过方法去访问数据,这样就可以增强程序的安全性.接下来演示未使用封装可能出现的问题,如例所示. 在例中,运行结果输出的成绩为-68,在程序中不会有任 ...

  9. 14.11 基类与派生类关系的详细再探讨

    一:派生类对象模型简述 Men mymen:子类(派生类对象),包含多个组成部分(也就是多个子对象); <1>一个是含有派生类自己定义的成员变量,成员函数的子对象: <2>一个 ...

  10. C++ 抽象基类与派生类

    抽象基类与派生类:构造方法的注意事项 1.抽象基类的构造方法不要用纯虚函数 2.子类的属性名如果和抽象基类的属性名相同的情况下 (1).使用子类对象调用此属性时会优先调用子类的属性 (2).在构造方法 ...

最新文章

  1. python语言deLong‘s test:通过统计学的角度来比较两个ROC曲线、检验两个ROC曲线的差异是否具有统计显著性
  2. win10安装mysql无服务_win10装sql没有SQL Server 服务
  3. 使用CSS3悬停效果打造不同的页面版式
  4. 【Linux 内核 内存管理】内存管理架构 ⑤ ( sbrk 内存分配系统调用代码示例 | 在 /proc/pid/maps 中查看进程堆内存详情 )
  5. matlab下删除文件或文件夹
  6. mysql 导入主键冲突_MySQL 处理插入过程中的主键唯一键重复值的解决方法
  7. html5 audio音频播放全解析
  8. Android—Gson原理解析
  9. 复制粘贴不连续单元格_表格筛选状态下怎么复制粘贴数据
  10. python中安装包出现Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None))…………
  11. [Unity3D] DOTween和Curvy插件,以及UI-Extension
  12. 把标清视频转高清Video Enhance AI for mac
  13. 【CSP】201903-1 小中大
  14. 【数学模拟卷总结】2022李林四套卷数学二第一套
  15. WFD抓包及视频提取
  16. UI设计师注意,网站头图的10个黄金法则
  17. VisionPro使用C#编写脚本
  18. AD2019 层次原理图
  19. Java进阶教程-马士兵
  20. Java中的引用:强软弱虚

热门文章

  1. 【语音SBC算法】基于正交滤波器组的语音SBC算法设计与实现
  2. PDF转Word技巧,看这篇足够
  3. Universal Windows Platform(UWP)应用的窗口特性
  4. 硬分叉升级越来越近,BCH社区都在做什么?
  5. 高通暂时不会针对物联网打造专属处理器
  6. 服务器负载均衡的部署方式
  7. Android自动化测试工具Appium环境搭建
  8. 黄聪:C# 开发Chrome内核浏览器(WebKit.net)
  9. STL标准容器类简介
  10. 程序是在RAM里还是flash里执行