C++之继承、派生

news2025/7/28 6:06:14

目录

1.继承的概念与定义

2.层次概念是计算机的重要概念:

3.私有的能被继承,不能被访问

 4.继承的三步骤

1.继承语法

2.继承例子

5.有继承和组合的构造顺序---内存布局

6.继承之下的赋值运算符重载

1.基础知识

 2.Person、Student例子

7.一个类被多个类继承


1.继承的概念与定义

继承和派生:(继承和派生一体两面)

继承(inheritance)机制:是类型层次结构设计中实现代码的复用重要手段。

class 子类: 继承权限 基类
 {
};
继承:
* 1.一个类自动拥有了来自另外一个类的属性和方法
* 2.一个类是一个类
* 层次关系-继承、派生

继承:
1、基类的处理构造和析构之外,其他的全盘继承
2、是否能被子类的成员函数访问
3、是否能被外界访问

基类的权限        public           protected         private——继承权限

 public               public            protected         private
 protected         protected      protected          private
 private             不可访问       不可访问          不可访问

派生:保持原有类特性的基础上进行扩展,增加新属性和新方法,从而产生新的类型。

在面向对象程序设计中,继承和派生是构造出新类型的过程。呈现类型设计的层次结构,体现了程 序设计人员对现实世界由简单到复杂的认识过程。

2.层次概念是计算机的重要概念:

C++ 通过类派生( class derivation)的机制来支持继承。被继承的类称为基类(base class)或超 类(superclass),新产生的类为派生类(derived class)或子类(subclass)。基类和派生类的集合 称作类继承层次结构(hierarchy)。

由基类派生出,派生类的设计形式为:

class 派生类名:访问限定符 基类名
{
private:
	成员表1; //派生类增加或替代的私有成员
public:
	成员表2; //派生类增加或替代的公有成员
protected:
	成员表3; //派生类增加或替代的保护成员
};//分号不可少

3.私有的能被继承,不能被访问


class A
{
public:
	int m_i;
	void print()
	{
		cout << "A::print" << endl;
	}
protected:
	int m_j;
private:
	int m_k;
};
class B :public A
{
	void set()
	{
		m_i = 10;
		m_j = 30;
		//m_k = 15;
	}
};
class C :protected A
{
	void set()
	{
		m_i = 10;
		m_j = 30;
		//m_k = 15;
	}
};
class D :private A
{
	void fn()
	{
		m_i = 10;
		m_j = 30;
		//m_k = 15;
	}
};
class CC :protected C
{
public:
	void ff()
	{
		m_i = 12;
		m_j = 23;
		//m_k = 15;
	}
};
class DD :public D
{
public:
	void ff()
	{
		
		//m_i = 12;
		//m_j = 23;
		//m_k = 15;
	}
};

//如果是私有继承,只能继承,不能使用
//继承除了构造和析构全盘接收
void main()
{
	cout << sizeof(B) << endl;
	B b;
	b.print();
	b.m_i = 12;
	//b.m_j = 23;
	//b.m_k = 34;
	C c;
	//c将属性m_i变成protected
	c.m_i = 12;
	c.m_j = 23;
	c.m_k = 34;}

class B :public  A//如果没有说明,默认私有继承
 //m_k = 15;//私有的能被继承,不能被访问
class DD :public D
{
public:
    void ff()
    {
        //在上一次继承被私有化了,不能再继承、访问
        //m_i = 12;
        //m_j = 23;
        //m_k = 15;
    }
};
//b.m_j = 23;//保护的在外界不能使用
C c;
//c将属性m_i变成protected
c.m_k = 34;//将C被保护继承

 4.继承的三步骤

* 1.除了构造和析构全盘接收
* 2.改写
* 3.添加子类特有的

1.继承语法

class 派生类名:[继承方式] 基类名{ 派生类新增加的成员 };

代码如下:


class A
{
public:
	A()
	{
		cout << "A" << endl;
	}
	void print()
	{
		cout << "A::print" << endl;
	}
	~A()
	{
		cout << "~A" << endl;
	}
private:
	int m_i;

};
class B : public A
{
public:
	B()
	{
		cout << "B" << endl;
	}
	~B()
	{
		cout << "~B" << endl;
	}
private:
	int m_j;
};
void main()
{
	B b;
}

 

 因为子类继承父类的时候,先运行父类构造函数;具体的说就是运行父类时就会先“调用”父类的构造函数,注意“调用”和继承不是一个含义,实质上是“自动运行”。

2.继承例子


class Person
{
public:
	Person(int num,const char*name,char sex) :m_num(num), m_sex(sex)
	{
		m_name = new char[strlen(name) + 1];
		strcpy_s(m_name, strlen(name) + 1, name);
	}
	~Person()
	{
		if (m_name != NULL)
		{
			delete[]m_name;
			m_name = NULL;
		}
	}
	Person(const Person& p) :m_num(p.m_num), m_sex(p.m_sex)
	{
		m_name = new char[strlen(p.m_name) + 1];
		strcpy_s(m_name, strlen(p.m_name) + 1, p.m_name);
	}
	void Show()
	{
		cout << m_num << " " << m_name << " " << m_sex << endl;
	}
private:
	int m_num;
	char* m_name;
	char m_sex;
};

class Student :public Person
{
public:
	Student(int num, const char* name, char sex, float score)
		:Person(num,name,sex),m_score(score)
	{

	}
	Student(Student& s) :Person(s)
	{
		m_score = s.m_score;
	}
	void Print()
	{
		Show();
		cout << m_score << endl;
	}
private:
	float m_score;
};
void main()
{
	Student s1(1001, "zhaowawa", 'f', 15);
	s1.Print();
	Student s2(s1);
	s2.Print();
}

 

 Student类公有继承了Person类中的num、name、sex,并且扩展了score。

5.有继承和组合的构造顺序---内存布局

* 1.先按照继承顺序调用基类构造
* 2.按照组合顺序调用组合的构造
* 3.调用自己的构造

class CPU
{
public:
	CPU() { cout << "CPU" << endl; }
};
class KB
{
public:
	KB() { cout << "KB" << endl; }
};
class Mouse
{
public:
	Mouse() { cout << "Mouse" << endl; }
};
class Computer
{
public:
	Computer() { cout << "Computer" << endl; }
private:
	CPU cpu;
	KB kb;
	Mouse ms;
}; 
class Touch
{
public:
	Touch() { cout << "Touch" << endl; }
};
class Laptop :public Computer
{
public:
	Laptop() { cout << "Laptop" << endl; }
private:
	Touch tc;
};
void main()
{
	Laptop lp;
}

1.调用基类,2.按照组合顺序得到:

CPU
KB
Mouse
Computer

3.调用自己的构造

Touch
Laptop

6.继承之下的赋值运算符重载

1.基础知识


class A
{
public:
	void Print()
	{
		cout << "A::Print" << endl;
	}
protected:
	int m_i;
};
/*
*隐藏:
*/
class B :public A
{
public:
	//B::Print将A::Print隐藏了
	void Print()
	{
		cout << "B::Print" << endl;
		cout << m_i << " " << A::m_i << endl;
	}
	void set()
	{
		m_i = 10;
		A::m_i = 20;
	}
protected:
	int m_i;
};

void main()
{
	A a;
	B b;
	a.Print();
	b.set();
	b.A::Print();
	b.Print();
	cout << sizeof(A) << endl;//4
	cout << sizeof(B) << endl;//8
}

//B::Print将A::Print隐藏了

A::Print      a.Print();
A::Print      b.A::Print();//B调用A::Print
B::Print      b.Print();
10 20         b.set();、b.Print();
4                int m_i;的大小
8                既继承了A中的m_i,B自己构造了成员

 2.Person、Student例子


class Person
{
public:
	
	Person() :m_sex('f'), m_age(20)
	{
		m_name = new char[1];
		*m_name = '\0';
		cout << "Person()" << endl;
	}
	Person(const char* name,char sex,int age):m_sex(sex), m_age(age)
	{
		m_name = new char[strlen(name) + 1];
		strcpy_s(m_name, strlen(name) + 1, name);
	}
	Person(Person& p) :m_sex(p.m_sex), m_age(p.m_age)
	{
		m_name = new char[strlen(p.m_name) + 1];
		strcpy_s(m_name, strlen(p.m_name) + 1, p.m_name);
	}
	Person& operator=(Person& p)
	{
		if (this == &p)
			return *this;
		delete[]m_name;
		m_name = new char[strlen(p.m_name) + 1];
		strcpy_s(m_name, strlen(p.m_name) + 1, p.m_name);
		m_sex = p.m_sex;
		m_age = p.m_age;
		return *this;
	}
	void Print()
	{
		cout << m_name << " " << m_sex << " " << m_age << endl;
	}
	~Person()
	{
		if (m_name != NULL)
		{
			delete[]m_name;
			m_name = NULL;
		}
	}
private:
	char* m_name;
	char m_sex;
	int m_age;
};
class Student :public Person
{
public:
	Student() :m_num(0), m_score(0)
	{
		cout << "Student()" << endl;
	}
	Student(int num,const char*name,char sex,int age,int score):m_num(num),Person(name,sex,age),m_score(score)
	{

	}
	void Print()
	{
		cout << m_num << " ";
		Person::Print();
		cout << m_score << endl;
	}
	Student(Student& s) :Person(s), m_num(s.m_num), m_score(s.m_score)
	{

	}
	Student& operator=(Student& s)
	{
		if (this == &s)
			return *this;
		Person::operator=(s);
		m_num = s.m_num;
		m_score = s.m_score;
		return *this;
	}
private:
	int m_num;
	int m_score;
};
void main()
{
	Student s;
	Student s1(1001, "zhangsan", 'f', 20, 78);
	s.Print();
	s1.Print();
	Student s2(s1);
	s2.Print();
	s = s1;
	s.Print();
}

Person()                     先调用基类
Student()                    构造s对象
0  f 20                         没有给s对象赋值,为构造函数的默认值
0
1001 zhangsan f 20   打印s1对象
78
1001 zhangsan f 20   用s1对象拷贝构造s2对象,并将s2对象打印
78
1001 zhangsan f 20   将s1对象的值赋给s对象,并将s对象打印
78

为什么要给默认值?

Person() :m_sex('f'), m_age(20)
    {
        m_name = new char[1];
        *m_name = '\0';
        cout << "Person()" << endl;
    }

因为不写默认值没有指向合法的内存空间

void main()
{
    int* p;
    cout << p << endl;//error
}

7.一个类被多个类继承


class Person
{
public:
	Person(int num = 1000):m_num(num)
	{

	}
	void print()
	{
		cout << "count = " << m_count << endl;
	}
protected:
	int m_num;
	static int m_count;
};
int Person::m_count;
class Student:public Person
{
public:
	Student(int num, const char*job) :Person(num)
	{
		m_job = new char[strlen(job) + 1];
		strcpy_s(m_job, strlen(job) + 1, job);
		m_count++;
	}
private:
	char* m_job;
};
class Teacher :public Person
{
public:
	Teacher(int num, const char* job) :Person(num)
	{
		m_job = new char[strlen(job) + 1];
		strcpy_s(m_job, strlen(job) + 1, job);
		m_count++;
	}
private:
	char* m_job;
};
class Worker :public Person
{
public:
	Worker(int num, const char* job) :Person(num)
	{
		m_job = new char[strlen(job) + 1];
		strcpy_s(m_job, strlen(job) + 1, job);
		m_count++;
	}
private:
	char* m_job;
};
void main()
{
	Student s(1001, "student");
	Teacher t(1002, "teacher");
	Worker w(1003, "worker");
	w.print();
	s.print();
	Worker w1(1006, "worker");
	s.print();
	cout << sizeof(Worker) << endl;//8
}

count = 3      static成员只构造一次
count = 3      每构造一个继承了Person的对象,count++
count = 4      增加了一名Worker
8                   Person 的num+Worker的job

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/16469.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

22.11.18打卡 [传智杯 #3 初赛] 部分题

森林图论懒得写, 等搞完dp之后再来复习图论, 还有一题数据有问题没写 [传智杯 #3 初赛] 课程报名 - 洛谷 哇真的签到, 第一眼还想着推公式呢, 看这数据范围直接暴力了 /* ⣿⣿⣿⣿⣿⣿⡷⣯⢿⣿⣷⣻⢯⣿⡽⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⠸⣿⣿⣆⠹⣿⣿⢾⣟⣯⣿⣿…

LiveGBS/LiveNVR组合实现GB35114平台端和GB35114设备端的GB35114的交互流程

概述&#xff1a; GB35114是在GB28181基础上扩展而来&#xff0c;增加了身份认证和数据加密。LiveNVR设备通过GB35114注册到LiveGBS时&#xff0c;LiveGBS平台端需要校验LiveNVR设备的身份&#xff0c;这是单向认证。同时可选LiveNVR也检验LiveGBS平台的身份&#xff0c;如果互…

[Howto] Pytorch Window GPU 环境配置

注&#xff1a; how to 系列只有基本的操作&#xff0c;不涉及原理&#xff0c;类似于操作手册。 Linux&#xff0c;MacOS和Window配置方法差不多&#xff0c;就是环境变量的修改方式不太一样&#xff0c;就不单独说明了。 1. 确定Pytorch版本 估计像我一样的初学者&#xf…

关于commonjs、AMD、UMD、ESM以及ts模块之间的使用差异

commonjs 特点&#xff1a;一个文件就是一个模块&#xff0c;拥有独立的作用域&#xff0c;适用于服务端不适合浏览器端。导出模块内部数据通过module.exports或exports对象默认导出&#xff1a; // true const a 1 const b 2 module.exports {a, b }或者 // true const …

【跨境电商卖家】Instagram营销初学者指南(二):方法与技巧

关键词&#xff1a;跨境电商卖家、instagram营销 1.为 Instagram营销设定目标 在你开始在 Instagram 上发帖之前&#xff0c;问问你自己&#xff08;或你的团队&#xff09;一件事&#xff1a;你为什么在 Instagram 上&#xff1f;尽管该平台很受欢迎&#xff0c;但您的回答不…

linux笔记(6):东山哪吒D1H显示HDMI测试-命令行调试

文章目录1.测试流程和结果2.测试过程详解2.1 挂载测试工具1.2 设置参数1.2.1设置name1.2.2选择命令1.2.3 设置命令参数1.3开启显示3.还没搞清楚怎么在应用中显示字符测试开发板的HDMI输出。 参考文档&#xff1a;全志官方文档。 1.测试流程和结果 测试结果&#xff1a; 2.测…

如何实现一键全选

利用复选框的激活、非激活实现一键全选功能 效果展示 前置准备 投票列表素材 具体步骤 添加素材 制作列表复选框 制作一件全选按钮 创建复选框相关行为触发器 制作一键全选触发器 步骤分解 添加素材 拖拽 图片组件 到 根容器 选中 图片组件 铺满父级容器 点击 检查面板 中的 …

一种新的群体智能优化算法:麻雀搜索算法(SSA)(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

C++中函数调用的整个过程内存堆栈分配详解

函数调用过程中&#xff1a;实参将值拷贝给函数的形参&#xff0c;而函数的形参相当于一个生存周期位于函数 内部的局部变量&#xff0c;函数内部的内存操作也只是将拷贝到形参的值进行操作&#xff0c;形参在函数结束 后会被栈自动回收释放(形参在栈中分配)&#xff0c;这就是…

Spring Security如何防止会话固定攻击

在春季安全课程的这篇文章中&#xff0c;我们将研究春季安全会话固定以及如何防止春季应用程序中的会话劫持。 春季安全会话固定 会话固定是一种非常常见且最常见的攻击类型&#xff0c;恶意攻击者可以通过访问站点来创建会话&#xff0c;然后诱使其他用户使用相同的会话登录…

副业是刚需?分享几个程序员接外包私活的网站

经常看到某某程序员接了个项目开发&#xff0c;工作之余轻轻松松赚了钱还顺带提升了技术&#xff1b;或者看到某大佬又发表了一篇程序员技术提升稿件&#xff0c;阅读点赞收藏三连发&#xff0c;这个月的零花钱又不愁了...但自己只是一名普普通通的程序员&#xff0c;能找到这样…

Golang入门笔记(10)—— 闭包 closure

先看一段代码&#xff0c;脱离代码讲闭包&#xff0c;太干了。 package mainimport "fmt"func main() {a : Adder()fmt.Println(a(1))fmt.Println(a(2))fmt.Println(a(3)) }func Adder() func(int) int { // 累加器&#xff1a;这里从10开始累加var sum int 10retu…

linux时区相关

背景&#xff1a;用linux自带的时间接口函数读取时间的时候&#xff0c;发现有时候时间与北京时间不符合&#xff0c;经过研究发现&#xff1a;时间 UTC时间时区带来的偏移。操作方法&#xff1a;timedatectl list-timezones可看支持的时区改时区方法有如下两种&#xff1a; l…

【LeetCode 每日一题】15. 三数之和

01 题目描述 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元…

【数据结构】链表LinkedList

1.ArrayList的缺陷 2.单链表的实现 3.LinkedList的使用&#xff08;模拟实现&#xff09; 我们之前介绍过ArrayList了&#xff0c;它的底层是数组&#xff0c;数组是一段连续的空间&#xff0c;当我们想要插入或者删除数据的时候&#xff0c;插入元素&#xff0c;就要让插入位置…

用树莓派PICO做一个桌面时钟超详细教程!

用树莓派PICO做一个可显示时间和温湿度的桌面时钟一、概述二、材料准备1、树莓派PICO2、DHT11温湿度传感器3、DS1302时钟模块&#xff08;选用&#xff09;4、SSD1306屏幕5、其他材料三、开始1、连线2、写程序&#xff08;1&#xff09;使用内置RTC函数实现的时钟&#xff08;2…

2.11 教你一套怎么建立自己的选题素材库的方法【玩赚小红书】

一、自身定位延伸选题库 建立选题库&#xff0c;前提先确定自身定位&#xff0c;然后发散性思维延展。如我们做母婴博主&#xff0c;接下来就要想&#xff0c;母婴用户会关注什么&#xff0c;自然会想到到宝宝吃喝玩乐、妈妈保养、产后修复、婆媳关系等等内容。若我们只做宝宝…

这才是,真彩虹预染蛋白Markers

做WB的小伙伴都知道&#xff0c;现市面上各种“多彩”Marker的产品有很多&#xff0c;但是真正拿到手上的&#xff0c;可能是各种各样的&#xff08;见图1&#xff09;&#xff0c;咱也不清楚哪个是真的... 现在小编告诉你&#xff0c;经典的彩虹Marker长这样(见图2)&#xff1…

WebDAV之葫芦儿·派盘+读出通知

读出通知 支持webdav方式连接葫芦儿派盘。 手机各种推销通知太多,如何避免那些繁琐的通知内容,做出一键就能够阅读重要通知的最佳体验,帮助您更加快速和便捷的体验到那些应用内容?推荐大家使用读出通知。 读出通知APP可以设置接收通知的app,还可以用耳机操作,操作简单…

avalanche 少量tcp长连接持续构建HTTP请求测试

最近测试项目&#xff0c;测试要求使用少量tcp长连接连接&#xff0c;持续打HTTP请求&#xff0c;到测试结束。 分别用思博伦测试仪和supernova测试仪进行实现。 思博伦测试仪实现 测试仪基本运行流程&#xff1a;Loads配置任何形式bandwidth&#xff0c;connection&#xf…