首页 > 编程语言 >C++派生类与继承性

C++派生类与继承性

时间:2024-06-04 12:59:11浏览次数:26  
标签:继承 成员 派生类 C++ class 基类 继承性 public

继承和派生其实都是一回事,只是说法不同罢了。
        如:子类继承了父类,父类派生了子类。

那么什么是继承呢

 首先,如上图所示是一个动物种类区分图。猫和狗都属于动物这一种类,而猫又可以细分为加菲猫、布偶猫等种类。我们发现这些细分出来的单体在拥有上一级别的共性之外,还有各自的共性。比如加菲猫和布偶猫体型、毛发品质不同,但他们都属于猫类。
        在编写代码的时候类与类之间也一样,子类拥有上一级类的共性,又拥有自己的特性!这个时候就可以利用继承的特性减少代码的重复性!!

一、基类 & 派生类
        当创建一个类时,不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。

        例如我们看到很多网站中,都有公共的头部,公共的底部,甚至公共的左侧列表,只有中心内容不同。

#include <iostream>
using namespace std;
 
//基类
class basepage {
	public:
		void header()
		{
			cout << "首页、公开课、登录、注册...(公共头部)" << endl;
		}
		void footer()
		{
			cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
		}
		void left()
		{
			cout << "Java,Python,C++...(公共分类列表)" << endl;
		}
};
 
//派生类
class CPP :public basepage {
public:
	void content() {
		cout << "C++学科视频" << endl;
	}
};
 
void test01()
{
	//C++页面
	cout << "C++下载视频页面如下: " << endl;
	CPP cp;
	cp.header();
	cp.footer();
	cp.left();
	cp.content();
}
 
int main() {
	test01();
	system("pause");
	return 0;
}
 
 

从运行结果可以看出,CPP类在定义自己的特性基础上还保留basepage类的属性,这就是派生的基本用法。

        一个类可以派生自多个类,这意味着,它可以从多个基类继承数据和函数。定义一个派生类,我们使用一个类派生列表来指定基类。类派生列表以一个或多个基类命名,形式如下:

class 派生类名:继承方式 基类名

                     

   其中继承属性有public、private、protected三种 。

多继承的方式如下:

        语法:class 派生类:继承方式 基类1 ,继承方式 基类2

二、继承方式
        前面说了类的继承方式有三种public、private、protected,他们的区别就是派生类对基类的访问权限有所不同!

公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
保护继承(protected): 当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。
私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。
        代码如下:

#include <iostream>
using namespace std;
 
//
//**继承方式一共有三种:**
//
//* 公共继承
//* 保护继承
//* 私有继承
 
class base1 {
public:
	int m_a;
protected:
	int m_b;
private:
	int m_c;
};
 
//公有派生
class son1 :public base1 {
public:
	void func() {
		m_a;	//可访问public权限
		m_b;	//可访问protected权限
		//m_c;	//m_c是基类的私有权限无法访问
	}
};
 
//保护派生
class son2 :protected base1 {
public:
	void func() {
		m_a;	//可访问protected权限
		m_b;	//可访问protected权限
		//m_c;	//m_c是基类的私有权限无法访问
	}
};
 
//保护派生
class son3 :private base1 {
public:
	void func() {
		//m_a;	//不可访问private权限
		//m_b;	//不可访问private权限
		//m_c;	//m_c是基类的私有权限无法访问
	}
};
 
 
void test() {
	son1 s;
	s.m_a;
	//s.m_b; 公有派生不改变成员变量的权限,因此m_b是保护权限,类外无法访问
 
	son2 s1;
	//s1.m_a;	//protected权限,类外无法访问
}
 
int main()
{
	system("pause");
	return 0;
}

  

三、继承的对象模型
        从父类继承过来的成员变量,哪些属于子类对象中?我们已经知道当发生公有继承的时候,不会改变基类成员变量的访问权限。
        并且在派生类中,无法访问基类中private属性的成员变量。无法访问并不意味着没有继承到派生对象中。可以看到如下代码:
                        
 

#include <iostream>
using namespace std;
 
//基类
class base {
public:
	int m_a;
protected:
	int m_b;
private:
	int m_c;
};
 
class son1 :private base {
public:
	int m_d;
};
 
void test() {
	cout << "son1 的 size = " << sizeof(son1) << endl;
}
 
int main()
{
	test();
	system("pause");
	return 0;
}

 运行结果:

         可以看出类son1的大小有16个字节,可以得出结论:派生类会继承基类中的private权限的成员变量。

        一个派生类继承了所有的基类方法,但如下三种情况除外:

基类的构造函数、析构函数和拷贝构造函数。
基类的重载运算符。
基类的友元函数。

四、基类和派生类构造/析构函数执行的顺序

#include <iostream>
using namespace std;
 
class base {
public:
	base() {
		cout << "base构造函数" << endl;
	}
	~base() {
		cout << "base析构函数" << endl;
	}
};
 
class son :public base {
public:
	son() {
		cout << "son构造函数" << endl;
	}
 
	~son() {
		cout << "son析构函数" << endl;
	}
};
 
void test() {
	son b1;
}
 
int main()
{
	test();
	system("pause");
	return 0;
}

 

五、同名成员变量(函数)的处理
        有时候我们会遇到派生类和基类出现同名成员函数和成员变量的问题,这时派生类会隐藏基类类中所有版本的同名成员函数。
        即在派生类定义的对象中访问同名成员变量(函数)的时候,执行的是派生类中。如果想访问基类中的成员变量(函数),就需要基类作用域。

#include <iostream>
using namespace std;
 
class base {
public:
	base() {
		m_a = 100;
	}
	void func() {
		cout << "base -func()的调用" << endl;
	}
 
	void func(int a) {
		cout << "base -func(int a)的调用" << endl;
	}
public:
	int m_a;
};
 
class son :public base {
public:
	son() {
		m_a = 200;
	}
 
	//当子类与父类拥有同名的成员函数,子类会隐藏父类中所有版本的同名成员函数
	//如果想访问父类中被隐藏的同名成员函数,需要加父类的作用域
	void func()
	{
		cout << "Son - func()调用" << endl;
	}
 
public:
	int m_a;
};
 
void test01() {
	son s;
 
	cout << "son下的 m_a:" << s.m_a << endl;
	cout << "base下的 m_a:" << s.base::m_a << endl;
 
	s.func();
	s.base::func();
	s.base::func(10);
}
 
int main()
{
	test01();
	system("pause");
	return 0;
}

 运行结果:

六、同名静态成员变量(函数)的处理
        除了遇到同名成员变量(函数),有时还会遇到同名的静态成员变量(函数)。与前者相似,为了访问基类的同名对象,需要加上作用域。只不过静态成员变量(函数)有两种访问方式:

        ①通过对象访问
        ②通过类名访问

#include <iostream>
using namespace std;
 
class base {
 
public:
	static void func() {
		cout << "base static void func()" << endl;
	}
	static void func(int a) {
		cout << "base static void func(int a)" << endl;
	}
 
public:
	static int m_a;
};
 
int base::m_a = 10;	/*类的静态成员变量,类内声明,类外定义*/
 
class son:public base {
public:
	static void func() {
		cout << "son static void func()" << endl;
	}
 
public:
	static int m_a;
};
 
int son::m_a = 20;
 
//同名静态成员属性
void test01() {
	//通过对象访问
	cout << "通过对象访问" << endl;
	son s1;
	cout << "son 下的m_a:" << s1.m_a << endl;
	cout << "base 下的m_a:" << s1.base::m_a << endl;
 
	//静态成员变量可以通过类名进行访问
	cout << "通过类名进行访问" << endl;
	cout << "son 下的m_a:" << son::m_a << endl;
	cout << "base 下的m_a:" << son::base::m_a << endl;
}
 
//同名静态成员函数
void test02() {
	//通过对象访问
	cout << "通过对象访问静态同名成员函数" << endl;
	son s2;
	s2.func();
	s2.base::func();
 
	//通过类名访问
	son::func();
	son::base::func();
	son::base::func(10);
}
 
int main()
{
	test01();
	test02();
	system("pause");
	return 0;
}

运行结果: 

七、菱形继承问题
        菱形继承,虚继承_audience_fzn的博客-CSDN博客

        两个派生类继承同一个基类,又有某个类同时继承两个派生类这种继承被称为菱形继承。这个时候,就会发生数据的二义性。

        因为最后的类继承了2次,原始基类的特性。为了解决这种情况引入了virtual关键字。代码如下:

#include <iostream>
using namespace std;
 
class animal {
public:
	int m_age;
 
};
 
//sheep继承animal
class sheep:virtual public animal {
 
};
 
class Tuo:virtual public animal {
 
};
 
class sheepTuo:public sheep, public Tuo {
 
};
 
void test01() {
	sheepTuo s;
	s.sheep::m_age = 100;
	s.Tuo::m_age = 200;
	cout << "s.sheep::m_age=" << s.sheep::m_age << endl;
	cout << "s.Tuo::m_age=" << s.Tuo::m_age << endl;
}
 
int main()
{
 
	test01();
	system("pause");
	return 0;
}

 

学习链接:https://blog.csdn.net/qq_42174306/article/details/122982391

 

标签:继承,成员,派生类,C++,class,基类,继承性,public
From: https://blog.csdn.net/2301_78986604/article/details/139398818

相关文章

  • 【第二节】C/C++数据结构之线性表
    目录一、线性表基本说明1.1基本概念1.2抽象数据类型1.3存储结构1.4插入与删除的区别1.5顺序存储和链式存储的优缺点二、链表2.1基本概念2.2抽象数据类型2.3单链表的定义2.4单链表的基本操作2.5单链表模板形式的类定义与实现三、单向循环链表四、双链表......
  • visual studio 2019 c++与汇编混合代码
    1、visualstudio2019下x64架构的CPU配置不支持内联汇编代码的嵌入,即不支持__asm{}语句。2、通过创建.asm汇编代码文件封装汇编函数的方式实现c++代码调用汇编函数:第一步:修改工程的生成依赖项第二步:创建.asm汇编代码文件第三步:编写汇编代码的函数第四步:在c++文件调用汇编函......
  • c++ 异常处理
     =================================【C++11】std::runtime_error的使用一、概要std::runtime_error:运行时错误异常类,只有在运行时才能检测到的错误,继承于std::exception,它的声明在头文件中。std::runtime_error也用作几个运行时错误异常的基类,包括std::range_error(生成的......
  • C/C++结构体对齐测试
    #include<stddef.h>#include<iostream>structs1{inta;intb;};#pragmapack(8)structs2{charc;inta;doubleb;};structs3{charb[10];doublea;};#pragmaunpackstructs4{c......
  • 小猴编程周赛C++ | 字符串
    学习C++从娃娃抓起!记录下在学而思小猴编程学习过程中的题目,记录每一个瞬间。侵权即删,谢谢支持!附上汇总贴:小猴编程C++|汇总-CSDN博客【题目描述】小猴最近学习了字符串,为了加强对字符串的理解,猴博士特意给小猴安排了一道编程题:给定一个字符串s,保证s中只包含大写字母(AZ......
  • 小猴编程周赛C++ | 六面世界
    学习C++从娃娃抓起!记录下在学而思小猴编程学习过程中的题目,记录每一个瞬间。侵权即删,谢谢支持!附上汇总贴:小猴编程C++|汇总-CSDN博客【题目描述】六面世界的地图由六边形格子组成,地图一共n行,奇数行有m格,偶数行有m-1格。下图是一个n=5,m=5的地图。小明想从起点S走到终点......
  • 《信息学奥赛一本通 编程启蒙C++版》3126-3130(5题)
    3126:练21.3 神奇装置信息学奥赛一本通-编程启蒙(C++版)在线评测系统练21.3神奇装置信息学奥赛一本通-编程启蒙(C++版)在线评测系统3126:练21.3神奇装置_哔哩哔哩_bilibili#include<bits/stdc++.h>usingnamespacestd;intmain(){ inta,b,c,d; cin>>a>>b>>c......
  • 《信息学奥赛一本通 编程启蒙C++版》3001-3280
    《信息学奥赛一本通编程启蒙C++版》3001-3005(5题)《信息学奥赛一本通编程启蒙C++版》3001-3005(5题)-CSDN博客《信息学奥赛一本通编程启蒙C++版》3006-3010(5题)《信息学奥赛一本通编程启蒙C++版》3006-3010(5题)-CSDN博客《信息学奥赛一本通编程启蒙C++版》3011-3015......
  • C/C++ for 语句的要点与注意事项
    C/C++中的 for 语句是一种常用的循环结构,用于重复执行一段代码,直到满足某个条件为止。以下是 for 语句的要点与注意事项:要点:基本语法:for 语句的基本语法为 for(initialization;condition;update){body_of_loop}。initialization:初始化循环控制变量。condition......
  • C++的vector使用优化
    我们在上一章说了如何使用这个vector动态数组,这章我们说说如何更好的使用它以及它是如何工作的。当你创建一个vector,然后使用push_back添加元素,当当前的vector的内存不够时,会从内存中的旧位置复制到内存中的新位置,然后删除删除旧位置的内存,也就是说当我push_back,vector容量不够......