【C++】类-派生和继承
类-派生和继承
1.基本概念
- 继承:保持已有类的特性而构造新类的过程
- 派生:在已有类的基础上新增自己的特性而产生新类的过程
2. 语法
单继承(一个父类)
/*
class 派生类名: 继承方式 基类名
{
成员声明;
}
*/
// eg:
class Derived: public Base
{
public:
Derived ();
~Derived ();
};
多继承(有多个父类)
/*
class 派生类名:继承方式1 基类名1,继承方式2 基类名2,...
{
成员声明;
}
*/
//eg:
class Derived: public Base1, private Base2
{
public:
Derived ();
~Derived ();
};
派生类的构成:
- 默认情况下继承除构造函数和析构函数以外的所有成员
- 派生类声明了一个和某基类成员同名的新成员,派生的新成员就隐藏或覆盖了外层同名成员
- 派生类增加新成员使派生类在功能上有所发展
3. 继承方式
不同继承方式的差别体现在:
- 派生类对基类成员的访问权限
- 通过派生类的对象对基类成员的访问权限
权限的优先级:public < protected < private。继承之后父类的成员在子类中的权限不低于继承方式的权限,即:
public不改变权限
protected:public——>protected
private:public, protected——>private
父类的private一直不能被子类访问
4. 类型转换
- 公有派生类对象可以被当作基类的对象使用,反之则不可。
- 派生类的对象可以隐含转换为基类对象;
- 派生类的对象可以初始化基类的引用;
- 派生类的指针可以隐含转换为基类的指针。
- 通过基类对象名、指针只能使用从基类继承的成员。
#include <iostream>
using namespace std; class Base1 { //基类Base1定义
public:
void display() const {
cout << "Base1::display()" << endl;
}
};
class Base2 : public Base1 { //公有派生类Base2定义
public:
void display() const {
cout << "Base2::display()" << endl;
}
};
class Derived : public Base2 { //公有派生类Derived定义
public:
void display() const {
cout << "Derived::display()" << endl;
}
};
void fun(Base1* ptr) { //参数为指向基类对象的指针
ptr->display(); //"对象指针->成员名"
}
int main() { //主函数
Base1 base1; //声明Base1类对象
Base2 base2; //声明Base2类对象
Derived derived; //声明Derived类对象
fun(&base1); //用Base1对象的指针调用fun函数
fun(&base2); //用Base2对象的指针调用fun函数
fun(&derived); //用Derived对象的指针调用fun函数
return 0;
}
都只能调用基类的display函数,即不要重写继承的非虚函数
5. 派生类的构造、析构函数
构造函数
默认情况下不继承基类的构造函数,使用
using Base::Base()
指定继承基类构造函数,此时只能用构造函数对基类成员初始化自行定义构造函数:
- 派生类新增成员:派生类定义构造函数初始化;
- 继承来的成员:自动调用基类构造函数进行初始化;
- 派生类的构造函数需要给基类的构造函数传递参数。
语法:多继承+组合类
派生类名::派生类名(形参表):
基类名1(参数), 基类名2(参数), ..., 基类名n(参数),
本类成员(含对象成员)初始化列表
{
//其他初始化
};
构造函数的执行顺序
调用基类构造函数。
顺序按照它们被继承时声明的顺序(从左向右)。
对初始化列表中的成员进行初始化。
顺序按照它们在类中定义的顺序。
对象成员初化时自动调用其所属类的构造函数。由初始化列表提供参数。
执行派生类的构造函数体中的内容。
复制构造函数
- 一般都要为基类的复制构造函数传递参数。
- 复制构造函数只能接受一个参数,既用来初始化派生类定义的成员,也将被传递给基类的复制构造函数。
- 基类的复制构造函数形参类型是基类对象的引用,实参可以是派生类对象的引用
析构函数
- 析构函数不被继承,派生类如果需要,要自行声明析构函数。
- 声明方法与无继承关系时类的析构函数相同。
- 不需要显式地调用基类的析构函数,系统会自动隐式调用。
- 先执行派生类析构函数的函数体,再调用基类的析构函数。
#include<iostream>
using namespace std;
class Base1 {
public:
Base1(int val) {
x = val;
cout << "Calling constructor of base1..." << endl;
}
Base1(Base1& a) {
x = a.x;
cout << "Calling copy constructor of base1..." << endl;
}
~Base1() {
cout << "Calling destructor of base1..." << endl;
}
private:
int x;
};
class Base2 {
public:
Base2(int val) {
y = val;
cout << "Calling constructor of base2..." << endl;
}
Base2(Base2& b) {
y = b.y;
cout << "Calling copy constructor of base2..." << endl;
}
~Base2() {
cout << "Calling destructor of base2..." << endl;
}
private:
int y;
};
class Derived:
public Base1, public Base2 {
public:
Derived(int val1, int val2, int val3) :
Base1(val1), Base2(val2) {
cout << "Calling constructor of derived..." << endl;
z = val3;
}
Derived(Derived& c) :
Base1(c), Base2(c) {
cout << "Calling copy constructor of derived..." << endl;
z = c.z;
}
~Derived() {
cout << "Calling destructor of derived..." << endl;
}
private:
int z;
};
int main() {
Derived d(1, 2, 2);
cout << "***********************" << endl;
Derived newd(d);
cout << "***********************" << endl;
return 0;
}
输出结果:
Calling constructor of base1...
Calling constructor of base2...
Calling constructor of derived...
Calling copy constructor of base1...
Calling copy constructor of base2...
Calling copy constructor of derived...
Calling destructor of derived...
Calling destructor of base2...
Calling destructor of base1...
Calling destructor of derived...
Calling destructor of base2...
Calling destructor of base1...
【C++】类-派生和继承的更多相关文章
- C++ 虚基类 派生与继承
在学习设计模式时我就有一个疑问,关联和继承除了用法上的区别,好像在内存上并没有什么区别,继承也是父类作为了子类的元素(内存上),关联也是这样.而且关联好像更占内存一些.这就是设计模式里问题了“依赖倒转 ...
- mfc 类三种继承方式下的访问
知识点 public private protected 三种继承方式 三种继承方式的区别 public 关键字意味着在其后声明的所有成员及对象都可以访问. private 关键字意味着除了该类型的创 ...
- C++学习6-面向对象编程基础(运算符重载、类的派生与继承、命名空间)
运算符重载 重载的运算符是具有特殊名字的函数:它们的名字由关键字operator和其后要定义的运算符号共同组成.重载的运算符是遵循函数重载的选择原则,根据不同类型或不同参数来选择不同的重载运算符. 运 ...
- C++学习19 类的多继承
在前面的例子中,派生类都只有一个基类,称为单继承.除此之外,C++也支持多继承,即一个派生类可以有两个或多个基类. 多继承容易让代码逻辑复杂.思路混乱,一直备受争议,中小型项目中较少使用,后来的 Ja ...
- 24 类:组合 继承 super关键字 面向对象的三大性
组合 组合:自定义类的对象作为另外一个类的属性 class Teacher: def __init__(self, name, age): self.name = name self.age = ag ...
- Java开发笔记(四十八)类的简单继承
前面介绍了类的基本用法,主要是如何封装一个类的各项要素,包括成员属性.成员方法.构造方法等,想必大家对类的简单运用早已驾轻就熟.所谓“物以类聚,人以群分”,之所以某些事物会聚在一起,乃是因为它们拥有类 ...
- Day 5-<补充> 类的的继承和查找顺序
类的继承于查找顺序: 在py2中,不继承object的类为经典类,经典类继承查找:深度优先. 在py3中,默认继承object,所以python3中都是新式类,新式类的继承查找:广度优先. 类的特殊属 ...
- 2015/9/22 Python基础(18):组合、派生和继承
一个类被定义后,目标就是把它当成一个模块来使用,并把这些对象嵌入到你的代码中去,同其他数据类型及逻辑执行流混合使用.有两种方法可以在你的代码中利用类.第一种是组合,就是让不同的类混合并加入到其他类中, ...
- OOP2(虚函数/抽象基类/访问控制与继承)
通常情况下,如果我们不适用某个函数,则无需为该函数提供定义.但我们必须为每个虚函数都提供定义而不管它是否被用到了,这因为连编译器也无法确定到底会适用哪个虚函数 对虚函数的调用可能在运行时才被解析: 当 ...
随机推荐
- js 将二维数组转为一维数组
方法一 使用ES的最新语法:Array.prototype.flat(). flat([dept]),参数 dept 为数组的深度,默认为1,根据传入的深度将数组展开. 对于不确定深度的数组,可以传入 ...
- vim操作(复制,粘贴)
整行操作 单行复制 在"命令"模式下,将光标移动到将要复制的行处,按"yy"进行复制 多行复制 在"命令"模式下,将光标移动到将要复制的首行 ...
- 谷歌protobuf(protocol-buffers)各种开发语言数据类型转换说明
官方文档:https://developers.google.cn/protocol-buffers/docs/proto proto2 proto3
- 【LeetCode】34. Find First and Last Position of Element in Sorted Array 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 二分查找 日期 题目地址:https://leetc ...
- 1137 - Expanding Rods
1137 - Expanding Rods PDF (English) Statistics Forum Time Limit: 0.5 second(s) Memory Limit: 32 M ...
- 利用shiro反序列化注入冰蝎内存马
利用shiro反序列化注入冰蝎内存马 文章首发先知社区:https://xz.aliyun.com/t/10696 一.shiro反序列化注入内存马 1)tomcat filter内存马 先来看一个普 ...
- [C++]C++四舍五入保留到n位小数
#include <sstream> #include <iostream> #include <iomanip> using namespace std; /** ...
- 新手入门typeScript
强类型与弱类型(类型安全) 强类型不允许随意的隐士类型转换,而弱类型是允许的 变量类型允许随时改变的特点,不是强弱类型的差异 静态类型与动态类型(类型检查) 静态类型:一个变量声明时它的类型就是明确的 ...
- SpringBoot集成Actuator端点配置
1.说明 Actuator端点可以监控应用程序并与之交互. Spring Boot包括许多内置的端点, 比如health端点提供基本的应用程序运行状况信息, 并允许添加自定义端点. 可以控制每个单独的 ...
- TortoiseGit使用ssh-keygen生成的私钥
1.说明 使用TortoiseGit自带的PuTTY Key Generator工具, 把ssh-keygen生成的私钥转换为Putty使用的.ppk文件, 然后在拉取Git代码时, 加载对应的.pp ...