C++ 基础 4:继承和派生
1 继承和派生
在 C++ 中 可重用性是通过继承这一机制实现的。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行效率的效果。
当创建一个类时,不需要重新编写新的数据成员和成员函数,只需指定 新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。
继承与派生,是同一种意义两种说法。继承代表了 is a 关系。例如,哺乳动物是动物,狗是哺乳动物,因此,狗是动物。
如:B 类继承 A 类,可称从类 A 派生类 B。类 A 称为基类(父类),类 B 称为派生类(子类)。
2 派生类的组成
派生类的成员,包含两大部分,一类是从基类继承过来的,一类是自己新增的成员。从基类继承过来的成员表现其共性,而新增的成员体现了其个性,派生类有了自己的个性,使派生类有了意义。
注意:
一个派生类继承了所有的基类方法,但下列情况除外:
基类的构造函数、析构函数和拷贝构造函数。
基类的重载运算符。
基类的友元函数。
3 继承类型
当一个类派生自基类,该基类可以被继承为 public、protected 或 private 几种类型。
公有继承(public):当类的继承方式为公有继承时,基类的公有和保护成员的访问属性在派生类中不变,而基类的私有成员不可访问。即基类的公有成员和保护成员被继承到派生类中仍作为派生类的公有成员和保护成员。派生类的其他成员可以直接访问它们。无论派生类的成员还是派生类的对象都无法访问基类的私有成员。
保护继承(protected): 保护继承中,基类的公有成员和私有成员都以保护成员的身份出现在派生类中,而基类的私有成员不可访问。派生类的其他成员可以直接访问从基类继承来的公有和保护成员,但是类外部通过派生类的对象无法访问它们,无论派生类的成员还是派生类的对象,都无法访问基类的私有成员。
私有继承(private):当类的继承方式为私有继承时,基类中的公有成员和保护成员都以私有成员身份出现在派生类中,而基类的私有成员在派生类中不可访问。基类的公有成员和保护成员被继承后作为派生类的私有成员,派生类的其他成员可以直接访问它们,但是在类外部通过派生类的对象无法访问。无论是派生类的成员还是通过派生类的对象,都无法访问从基类继承的私有成员。通过多次私有继承后,对于基类的成员都会成为不可访问。因此私有继承比较少用。
注意:
1. 无论何种方式继承基类,派生类都不能直接使用基类的私有成员。
2. 继承时,如果未使用访问修饰符,则继承类型默认为 private。
4 单继承
一个类可以派生自多个类,如果只派生一个,即为单继承。语法如下:
class 派生类名:继承类型 基类名
{
派生类类体;
};
继承类型即是访问修饰符,是 public、protected 或 private 其中的一个。如果未使用访问修饰符,则默认为 private。
假设有一个基类 Shape,Rectangle 是它的派生类,如下所示:
#include <iostream>
using namespace std;
// 基类
class Shape
{
public:
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
protected:
int width;
int height;
};
// 派生类
class Rectangle: public Shape
{
public:
int getArea()
{
return (width * height);
}
};
int main(void)
{
Rectangle Rect;
Rect.setWidth(5);
Rect.setHeight(7);
// 输出对象的面积
cout << "Total area: " << Rect.getArea() << endl;
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
Total area: 35
5 多继承
多继承即一个子类可以有多个父类,它继承了多个父类的特性。语法如下:
class 派生类名:继承类型1 基类名1,继承类型2 基类名2,...
{
派生类类体;
};
继承类型即是访问修饰符,是 public、protected 或 private 其中的一个。如果未使用访问修饰符,则默认为 private。
各个基类之间用逗号分隔。
假设有一个派生类 Rectangle 继承于 基类 Shape 与 基类 PaintCost,如下所示:
#include <iostream>
using namespace std;
// 基类 Shape
class Shape
{
public:
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
protected:
int width;
int height;
};
// 基类 PaintCost
class PaintCost
{
public:
int getCost(int area)
{
return area * 70;
}
};
// 派生类
class Rectangle: public Shape, public PaintCost
{
public:
int getArea()
{
return (width * height);
}
};
int main(void)
{
Rectangle Rect;
int area;
Rect.setWidth(5);
Rect.setHeight(7);
area = Rect.getArea();
// 输出对象的面积
cout << "Total area: " << Rect.getArea() << endl;
// 输出总花费
cout << "Total paint cost: $" << Rect.getCost(area) << endl;
return 0;
}
上面的代码被编译和执行时,它会产生下列结果:
Total area: 35
Total paint cost: $2450
6 虚继承
如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,则在对该基类中声明的名字进行访问时,可能产生二义性。
6.1 多继承中二义性问题

6.1.1 多重派生类 C 的对象的存储结构示意

6.2 虚继承 virtual
如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,则在对该基类中声明的名字进行访问时,可能产生二义性。
如果在多条继承路径上有一个公共的基类,那么在继承路径的某处汇合点,这个公共基类就会在派生类的对象中产生多个基类子对象。
要使这个公共基类在派生类中只产生一个子对象,必须对这个基类声明为虚继承,使这个基类称为虚基类。
虚继承声明使用关键字 virtual
语法如下:
class 类名: virtual 继承类型 父类名
继承类型即是访问修饰符,是 public、protected 或 private 其中的一个。如果未使用访问修饰符,则默认为 private。

6.2.1 带有虚基类的多重派生类 C 的对象的存储结构示意

7 继承中的构造和析构
7.1 类型兼容原则
类型兼容规则是指 在需要基类的任何地方,都可以使用公有(pulic)派生类的对象来替代。
类型兼容规则中所指的替代包括以下情况:
子类对象可以当做父类对象使用
子类对象可以直接赋值给父类对象
子类对象可以直接初始化父类对象
父类指针可以直接指向子类对象
父类引用可以直接引用子类对象
在替代之后,派生类对象就可以作为基类的对象使用,但是只能使用从基类继承的成员。
示例代码如下所示:
// inheritTest1.cpp,
// 用于验证类型兼容规则
/*
类型兼容规则中所指的替代包括以下情况:
1. 子类对象可以当做父类对象使用
2. 子类对象可以直接赋值给父类对象
3. 子类对象可以直接初始化父类对象
4. 父类指针可以直接指向子类对象
5. 父类引用可以直接引用子类对象
*/
#include <iostream>
using namespace std;
class Parent
{
public:
void printParent()
{
cout << "this is ParentClass" << endl;
}
int parent_age;
};
class Child : public Parent
{
public:
void printChild()
{
cout << "this is ChildClass" << endl;
}
};
void printByPoint(Parent *parent)
{
parent->printParent();
}
void printByReference(Parent& parent)
{
parent.printParent();
}
int main()
{
Child childTest_1;
childTest_1.printParent(); // 1. 子类对象可以当做父类对象使用
cout << "验证 子类对象可以当做父类对象使用 成功" << endl;
Child childTest_2;
childTest_2.parent_age = 18; // 2. 子类对象可以直接赋值给父类对象
cout << "验证 子类对象可以直接赋值给父类对象 成功" << endl;
Child childTest_3;
childTest_3.parent_age = 1; // 注意:子类对象初始化父类对象,必须对父类对象的公有成员也初始化,否则去掉这句会报错
Parent parentTest_3 = childTest_3; // 3. 子类对象可以直接初始化父类对象
cout << "验证 子类对象可以直接初始化父类对象 成功" << endl;
Child childTest_4;
Parent *parentTest_4 = NULL;
parentTest_4 = &childTest_4; // 4. 父类指针可以直接指向子类对象
printByPoint(parentTest_4);
cout << "验证 父类指针可以直接指向子类对象 成功" << endl;
Child childTest_5;
Parent &parentTest_5 =childTest_5; // 5. 父类引用可以直接引用子类对象
printByReference(parentTest_5);
cout << "验证 父类引用可以直接引用子类对象 成功" << endl;
return 0;
}
运行结果:

7.2 继承中构造析构调用原则
- 子类对象在创建时会首先调用父类的构造函数,父类构造函数执行结束后,执行子类的构造函数
2.当父类的构造函数有参数时,需要在子类的初始化列表中显式调用
3.析构函数调用的先后顺序与构造函数相反
示例代码如下所示:
// inheritTest2.cpp,继承中构造析构调用原则
#include <iostream>
using namespace std;
class Parent
{
public:
Parent(const char* temp_s)
{
this->s = temp_s;
cout << "父类有参构造函数运行"<< endl;
}
~Parent()
{
cout << "父类析构函数运行" << endl;
}
private:
const char* s;
};
class Child : public Parent
{
public:
Child(int temp_age):Parent("我是父类")
{
this->age = temp_age;
cout << "子类有参构造函数运行"<< endl;
}
Child(int temp_age,const char *temp_s):Parent(temp_s)
{
this->age = temp_age;
cout << "子类有参构造函数运行"<< endl;
}
~Child()
{
cout << "子类析构函数运行" << endl;
}
private:
int age;
};
int main()
{
Child child_1(18);
//Child child_2(18,"我是父类"); //这条语句也可实现
return 0;
}
运行结果:

C++ 基础 4:继承和派生的更多相关文章
- python 之 面向对象基础(继承与派生,经典类与新式类)
7.2 继承与派生 7.21继承 1.什么是继承? 继承是一种新建类的的方式,在python中支持一个子类继承多个父类.新建的类称为子类或者派生类,父类又可以称为基类或者超类,子类会”遗传“父类的属性 ...
- Python基础之继承与派生
一.什么是继承: 继承是一种创建新的类的方式,新建的类可以继承一个或过个父类,原始类成为基类或超类,新建的类则称为派生类 或子类. 其中,继承又分为:单继承和多继承. class parent_cla ...
- python基础——继承与派生、组合
python基础--继承与派生 1 什么是继承: 继承是一种创建新的类的方式,在python中,新建的类可以继承自一个或者多个父类,原始类成为基类或超累,新建的类成为派生类或子类 1.1 继承分为:单 ...
- Python开发基础-Day18继承派生、组合、接口和抽象类
类的继承与派生 经典类和新式类 在python3中,所有类默认继承object,但凡是继承了object类的子类,以及该子类的子类,都称为新式类(在python3中所有的类都是新式类) 没有继承obj ...
- python基础之继承派生、组合、接口和抽象类
类的继承与派生 经典类和新式类 在python3中,所有类默认继承object,但凡是继承了object类的子类,以及该子类的子类,都称为新式类(在python3中所有的类都是新式类) 没有继承obj ...
- C++基础之继承类和派生类
(1)继承是创建一个具有某个类的属性和行为的新类的能力.原有的类称为基类,新创建的类称为派生类.派生类将基类中的所有成员作为自己的成员,同时派生类本身可以定义新的成员(2)派生类只有一个基类的继承称单 ...
- 四.OC基础--1.文档安装和方法重载,2.self和super&static,3.继承和派生,4.实例变量修饰符 ,5.私有变量&私有方法,6.description方法
四.OC基础--1.文档安装和方法重载, 1. 在线安装 xcode-> 系统偏好设置->DownLoads->Doucument->下载 2. 离线安装 百度xcode文档 ...
- C/C++基础知识总结——继承与派生
1. 类的继承与派生 1.1 派生类的定义 (1) 定义规范 class 派生类名: 继承方式 基类1名, 继承方式 基类2名... { ...派生类成员声明; }; (2) 从以上形式上看可以多继承 ...
- python基础之类与对象,继承与派生
类与对象 对象的本质也就是一个名称空间而已,用于存放自己独有的属性,而类中存放的是对象共有的属性. __init__会在调用类时自动触发 调用类时发生两件事: 1.创建一个空对象stu1 2.自动触发 ...
- Python基础(16)_面向对象程序设计(类、继承、派生、组合、接口)
一.面向过程程序设计与面向对象程序设计 面向过程的程序设计:核心是过程,过程就解决问题的步骤,基于该思想设计程序就像是在设计一条流水线,是一种机械式的思维方式 优点:复杂的问题的简单化,流程化 缺点: ...
随机推荐
- Tensorflow学习笔记No.4.2
使用CNN卷积神经网络(2) 使用Tensorflow搭建简单的CNN卷积神经网络对fashion_mnist数据集进行分类 不了解是那么是CNN卷积神经网络的小伙伴可以参考上一篇博客(Tensorf ...
- SCOI 2008 【奖励关】
早上的考试一道都做不出,被教做人,心态爆炸ing...... 题目描述: 你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关.在这个奖励关里,系统将依次随机抛出k次宝物,每次你都可以选择吃或者不吃(必 ...
- linux 中 eclipse 开发 c/c++ 多线程程序,添加 libpthread.a 库支持
导入头文件 在 linux 中开发多线程程序,在使用到 pthread 系列函数的文件中,需要导入头文件: #include <pthread.h> 链接 libpthread.a 在编译 ...
- Fabric1.4.4 基础环境搭建
简单记录一下fabric版本1.4.4的环境搭建部署,运行环境为CentOs7.8,如有错误欢迎批评指正. 1.Docker 和 Docker Compose 1. docker的安装部署 docke ...
- C# 中 System.Range 结构体
翻译自 John Demetriou 2020年4月6日 的文章 <C# 8 Is Introducing Ranges> 我们之前讨论过的 C# 中的一个特性 System.Index ...
- linux块设备驱动---概念与框架(转)
基本概念 块设备(blockdevice) --- 是一种具有一定结构的随机存取设备,对这种设备的读写是按块进行的,他使用缓冲区来存放暂时的数据,待条件成熟后,从缓存一次性写入设备或者从设备一次性 ...
- DM9000网卡驱动分析(转)
s3c6410自带的DM9000网卡驱动也是基于platform设备模型. 其定义的设备资源在arch/arm/mach-s3c64xx/mach-smdk6410中.有网卡的resource res ...
- nfs4使用中的防火墙配置
一,查看本地centos的版本: [root@localhost lib]# cat /etc/redhat-release CentOS Linux release 8.1.1911 (Core) ...
- scrapy 采集数据存入excel
# -*- coding: utf-8 -*- # Define your item pipelines here # # Don't forget to add your pipeline to t ...
- 趣谈多线程(Python版)
温馨提示:本文篇幅较长,建议读者耐心阅读,本文中的代码经过笔者精心构思,可以复制过去运行一下,观察输出结果,所有代码在python3.5.0中测试通过. 文章目录 What is 多线程? Why w ...