IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> C++编程——继承 -> 正文阅读

[Java知识库]C++编程——继承


继承的知识点结构
在这里插入图片描述
继承是面向对象三大特性之一,例如动物类下可以有猫类、狗类。显然猫类、狗类都具有动物类的属性,于此同时,也就有自己独特的属性。这个时候,猫类、狗类就是继承于动物类, 采用继承的技术,可以减少重复的代码

1. 继承的基本语法

语法class 子类:继承方式 基类
继承示例
一般网页都有很多部分相似的,我们可以将这些相似的部分抽象出来,作为一个基类。然后子类只需要继承基类,在基类的基础上添加自身其他的属性或者方法就可以实现基本的功能,同时减少了重复代码。

//继承实现页面
//公共页面类
class BasePage
{
public:
	void header()
	{
		cout << "网页公共头部信息" << endl;
	}
	void footer()
	{
		cout << "网页公共底部信息" << endl;
	}
	void left()
	{
		cout << "网页公共分类列表信息" << endl;
	}
};


//Java页面
class Java :public BasePage
{
public:
	void content()
	{
		cout << "Java网页信息" << endl;
	}
};


//Python页面
class Python :public BasePage
{
public:
	void content()
	{
		cout << "Python网页信息" << endl;
	}
};


//CPP页面
class CPP :public BasePage
{
public:
	void content()
	{
		cout << "CPP网页信息" << endl;
	}
};

void test01()
{
	cout << "Java页面如下" << endl;
	Java ja;
	ja.header();
	ja.footer();
	ja.left();
	ja.content();

	cout << "Python页面如下" << endl;
	Python py;
	py.header();
	py.footer();
	py.left();
	py.content();

	cout << "CPP页面如下" << endl;
	CPP cp;
	cp.header();
	cp.footer();
	cp.left();
	cp.content();
}


int main()	
{
	test01();
	system("pause");
	return 0;
}

2. 继承方式

继承方式一共有三种:

  • 公共继承public
  • 保护继承protected
  • 私有继承private

:保护访问权限和私有访问权限都是类内可访问,类外不能访问。但是两者的不同点会在继承中体现。

下面将说明发生继承后,子类访问权限的变化情况:
基类

class A
{
public:
	int a;
protected:
	int b;
private:
	int c;
};
  • 公有方式继承基类
class B :public A
{
public:
	int a;
protected:
	int b;
不可访问:
	int c:
};
  • 保护方式继承基类
class B :protected A
{
protected:
	int a;
	int b;
不可访问:
	int c:
};
  • 私有方式继承基类
class B :private A
{
private:
	int a;
	int b;
不可访问:
	int c:
};

3. 继承的对象模型

问题:从父类继承过来的成员,哪些是属于子类对象的?

先来看一段代码:

class Base
{
public: 
	int m_A;
protected:
	int m_B;
private:
	int m_C;
};

class Son : public Base
{
public:
	int m_D;
};

void test01()
{
	cout << "size of Son = " << sizeof(Son) << endl;
}


int main()	
{
	test01();
	system("pause");
	return 0;
}

输出的结果如下:
在这里插入图片描述
可以得到以下结论:

  1. 父类中所有非静态成员属性都会被子类继承下去
  2. 父类中私有成员属性是被编译器给隐藏了,因此访问不到,但是确实是被继承下去了

利用开发工具验证继承的对象模型

  1. 打开Visual Studio的开发人员命令提示符
    在这里插入图片描述
    2.将路径定位到所要查看类对象模型所在文件夹的路径
    在这里插入图片描述
    3.输入代码:cl(l代表字母l) /d1(1代表数字1) reportSingleClassLayout类名 类所在的文件名,并得到结果
    在这里插入图片描述

4. 继承中构造和析构顺序

示例

//继承中的构造和析构顺序
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 test01()
{
	Son son;
}


int main()
{
	test01();
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述继承中的构造和析构顺序如下
先构造父类,再构造子类,析构的顺序与构造的顺序相反

5. 继承中同名成员处理

问题:当子类与父类出现同名成员,如何通过子类对象访问到子类或者父类中同名的数据呢?

  • 访问子类同名成员,直接访问即可
  • 访问父类同名成员,需要加作用域

示例

class Base
{
public:
	Base()
	{
		m_A = 100;
	}

	int m_A;
};


class Son :public Base
{
public:
	Son()
	{
		m_A = 200;
	}

	int m_A;
};


void test01()
{
	Son son;
	cout << "子类中的m_A = " << son.m_A << endl;
	cout << "父类中的m_A = " << son.Base::m_A << endl;
}


int main()
{
	test01();
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述
:同名成员函数的处理和同名成员属性的处理相同,要注意的是:如果子类中出现和父类同名的成员函数,子类的同名成员函数会隐藏掉父类中所有同名成员函数

6. 继承中同名静态成员处理方式

问题:继承中同名的静态成员在子类对象上如何进行访问?

静态成员和非静态成员出现同名时,处理方式一致

6.1 通过对象访问

class Base
{
public:
	static int m_A;
};
int Base::m_A = 100;


class Son :public Base
{
public:
	static int m_A;
};
int Son::m_A = 200;


void test01()
{
	Son s;
	cout << "子类中的静态成员m_A = " << s.m_A << endl;
	cout << "父类中的静态成员m_A = " << s.Base::m_A << endl;
}


int main()
{
	test01();
	system("pause");
	return 0;
}

6.2 通过类名访问

class Base
{
public:
	static int m_A;
};
int Base::m_A = 100;


class Son :public Base
{
public:
	static int m_A;
};
int Son::m_A = 200;


void test01()
{
	
	cout << "子类中的静态成员m_A = " << Son::m_A << endl;
	cout << "父类中的静态成员m_A = " << Son::Base::m_A << endl;
}


int main()
{
	test01();
	system("pause");
	return 0;
}

7. 多继承语法

C++允许一个类继承多个类
语法:class 子类: 继承方式 父类1, 继承方式 父类2 ...
:多继承可能会引发父类中有同名成员出现,需要加作用域区分,C++的实际开发中不建议用多继承的技术

7.1 多继承的对象模型

class Base1
{
public:
	Base1()
	{
		m_A = 100;
	}
	int m_A;
};



class Base2
{
public:
	Base2()
	{
		m_A = 200;
	}
	int m_A = 200;
};

class Son :public Base1,public Base2
{
public:
	Son()
	{
		m_C = 300;
		m_D = 400;
	}
	int m_C;
	int m_D;
};



void test01()
{
	Son s;
	cout << "sizeof Son = " << sizeof(s) << endl;
	cout << "Base1中的m_A = " << s.Base1::m_A << endl;
	cout << "Base2中的m_A = " << s.Base2::m_A << endl;
}

int main()
{
	test01();
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述

也可以利用开发者工具查看模型:
在这里插入图片描述

8. 菱形继承(钻石继承)

概念:两个派生类继承同一个基类,又有某个类同时继承着两个派生类

典型的菱形继承案例
动物作为基类,羊类和驼类作为动物的派生类,羊驼类同时继承羊类和驼类

菱形继承问题

  1. 羊继承了动物的数据,驼也同样继承了动物的数据,当羊驼使用数据时,就会产生二义性。
//动物类
class Animal
{
public:
	int m_Age;
};

//羊类
class Sheep: public Animal
{

};

//驼类
class Camel : public Animal
{

};

//羊驼类
class SheepCamel: public Sheep, public Camel
{
	
};


void test01()
{
	SheepCamel sc;
	sc.m_Age = 18; //这行代码就会报错,因此羊驼类继承了两份m_Age,直接调用sc.m_Age产生了二义性
	sc.Sheep::m_Age = 18;
	sc.Camel::m_Age = 20; //可以利用添加作用域的方式来解决二义性的问题
}


int main()
{
	test01();
	system("pause");
	return 0;
}
  1. 羊驼类实际上继承两份动物的数据,造成了内存的浪费(例如羊有年龄,驼也有年龄,羊驼都继承了羊类和驼类关于年龄的数据,但实际上羊驼的年龄只有一个,没有必要拥有两份关于年龄的数据)

可以参考多继承的对象模型:
在这里插入图片描述

采用虚基类解决菱形继承的问题
继承之前,加上关键字virtual变为虚继承

//动物类
class Animal
{
public:
	int m_Age;
};

//羊类
class Sheep:virtual public Animal
{

};

//驼类
class Camel :virtual public Animal
{

};

//羊驼类
class SheepCamel: public Sheep, public Camel
{
	
};


void test01()
{
	SheepCamel sc;
	sc.Sheep::m_Age = 18;
	sc.Camel::m_Age = 28;
	 
	cout << "sc.Sheep::m_Age = " << sc.Sheep::m_Age << endl;
	cout << "sc.Camel::m_Age = " << sc.Camel::m_Age << endl;
	cout << "sc.m_Age = " << sc.m_Age << endl;
}


int main()
{
	test01();
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述

说明:采用虚继承之后,菱形继承中羊驼类就只有一份年龄的数据了,解决了内存浪费的问题

虚继承的底层原理
我们利用开发者工具调出羊驼类的对象模型:
在这里插入图片描述
和未采用虚继承技术的对象模型相比,年龄的数据变成只有一份了,但是多了vbptr
vbptr称为虚基类指针,指针指向的是vbtable,也就是虚基类表,虚基类表中的内容其实就是一个偏移量

  • Sheep中的虚基类指针指向的虚基类表中的偏移量为8,(0+8=8)就找到了年龄数据的地址
  • Camel中的虚基类指针指向的虚基类表中的偏移量为4,(4+4=8)就找到了年龄数据的地址
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-26 11:28:38  更:2022-04-26 11:33:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:40:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码