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 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ 继承 -> 正文阅读

[C++知识库]C++ 继承

继承

减少重复的代码,提高代码复用性。

  • 语法:class 子类 : 继承方式 父类
  • News 子类 派生类
  • BasePage 父类 基类

继承方式

在这里插入图片描述

公共继承

  • 父类中公共权限,子类中变为公共权限
  • 父类中保护权限,子类中变为保护权限
  • 父类中私有权限,子类访问不到

保护继承

  • 父类中公共权限,子类中变为保护权限
  • 父类中保护权限,子类中变为保护权限
  • 父类中私有权限,子类访问不到

私有继承

  • 父类中公共权限,子类中变为私有权限
  • 父类中保护权限,子类中变为私有权限
  • 父类中私有权限,子类访问不到
#define _CRT_SECURE_NO_WARNINGS
#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 = 100; //父类中 公共权限 子类中变为  公共权限
		m_B = 100; //父类中 保护权限 子类中变为  保护权限
		//m_C = 100;// 父类中私有成员,子类无法访问
	}
};

void test01()
{
	Son1 s1;
	s1.m_A = 100; //在Son1中 m_A是公共权限  类外可以访问
	//s1.m_B = 100; //在Son1中 m_B是保护权限  类外不可以访问
}


/   保护继承  
class Base2
{
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C;
};

class Son2 : protected Base2
{
public:
	void func()
	{
		m_A = 100;//父类中 公共权限 子类中变为  保护权限
		m_B = 100;//父类中 保护权限 子类中变为  保护权限
		//m_C = 100;//父类中私有成员,子类无法访问
	}
};

void test01()
{
	Son2 s;
	//s.m_A = 100;  //子类中 保护权限 无法访问
	//s.m_B = 100;  //子类中 保护权限 无法访问
	//s.m_C = 100; //子类本身没有访问权限
}


/   私有继承  
class Base3
{
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C;
};
class Son3 :private Base3
{
public:
	void func()
	{
		m_A = 100;  //父类中 公共权限 子类中变为  私有权限
		m_B = 100;  //父类中 保护权限 子类中变为  私有权限
		//m_C = 100;//父类中私有成员,子类无法访问
	}
};
class GrandSon3 :public Son3
{
public:
	void func()
	{
		//m_A = 100;//在Son3中 已经变为私有权限,GrandSon3访问不到
		//m_B = 100;
	}
};
void test03()
{
	Son3 s;
	//s.m_A = 100;//在Son3中变为私有权限,类外访问不到
	//s.m_B = 100;//在Son3中变为私有权限,类外访问不到

}

int main(){



	system("pause");
	return EXIT_SUCCESS;
}

总结

protected、private方式的继承会增加父类中被子类继承下的成员方法及成员属性的访问级别,调整到对应的继承级别。public方式保持父类的级别进行继承。

继承中的对象模型

  1. 父类中的私有属性,子类是继承下去了,只不过由编译器给隐藏了,访问不到
  2. 可以利用开发人员工具查看对象模型
    在这里插入图片描述
  3. 打开开发人员命令工具并跳转到所要查看的文件对应的盘符
  4. 跳转文件路径 cd到文件路径下
  5. cl /d1 reportSingleClassLayout类名 文件名
    在这里插入图片描述
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Base
{
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C;  //父类中私有属性,子类访问不到,是由编译器给隐藏了
};

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


void test01()
{
	//4  8    12   16
	cout << "size of  Son = " << sizeof(Son) << endl; // 结果为16

}


int main() {

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

继承中的构造和析构

  1. 先调用父类默认构造,再调用其他成员构造, 再调用自身构造 ,析构的顺序与构造相反
class Base1
{
public:
	Base1()
	{
		cout << "Base1的构造函数调用" << endl;
	}
	~Base1()
	{
		cout << "Base1的析构函数调用" << endl;
	}
};

class Other
{
public:
	Other()
	{
		cout << "Other的构造函数调用" << endl;
	}

	~Other()
	{
		cout << "Other的析构函数调用" << endl;
	}
};

class Son1 :public Base1
{
public:
	Son1()
	{
		cout << "Son1的构造函数调用" << endl;
	}

	~Son1()
	{
		cout << "Son1的析构函数调用" << endl;
	}

	Other other;
};

void test()
{
	Son1 s; //先调用父类构造,再调用其他成员构造, 再调用自身构造 ,析构的顺序与构造相反
}

在这里插入图片描述

  1. 若父类中没有默认构造,子类继承后,可以利用初始化列表语法 ,显示调用父类中的其他构造函数

class Base2
{
public:
	Base2(int a)
	{
		this->m_A = a;
		cout << "Base2的构造函数调用" << endl;
	}
	int m_A;
};
class Son2 :public Base2
{
public:
	Son2(int a = 1000 ) :Base2(a)  //利用初始化列表语法  显示调用父类中的其他构造函数
	{
		cout << "Son2的构造函数调用" << endl;
	}
};
void test02()
{
	Son2 s;
	cout << s.m_A << endl;
}

  1. 父类中 构造、析构、拷贝构造 、operator= 是不会被子类继承下去的

继承中的同名成员处理

  1. 我们可以利用作用域 访问父类中的同名成员

class Base
{
public:
	Base()
	{
		this->m_A = 10;
	}

	void func()
	{
		cout << "Base中的func调用" << endl;
	}

	void func(int a)
	{
		cout << "Base中的func(int)调用" << endl;
	}

	int m_A;
};

class Son :public Base
{
public:

	Son()
	{
		this->m_A = 20;
	}

	void func()
	{
		cout << "Son中的func调用" << endl;
	}

	int m_A;
};


void test()
{
	Son s1;

	cout << "s1.m_A = " << s1.m_A << endl; //默认显示的是子类成员值

	//我们可以利用作用域 访问父类中的同名成员
	cout << "Base中的m_A = " << s1.Base::m_A << endl;
}

在这里插入图片描述

  1. 当子类重新定义了父类中的同名成员函数,子类的成员函数会隐藏掉父类中所有重载版本的同名成员,可以利用作用域显示指定调用
class Base
{
public:
	Base()
	{
		this->m_A = 10;
	}

	void func()
	{
		cout << "Base中的func调用" << endl;
	}

	void func(int a)
	{
		cout << "Base中的func(int)调用" << endl;
	}

	int m_A;
};

class Son :public Base
{
public:

	Son()
	{
		this->m_A = 20;
	}

	void func()
	{
		cout << "Son中的func调用" << endl;
	}

	int m_A;
};
void test()
{
    //当子类重新定义了父类中的同名成员函数,子类的成员函数会 隐藏掉父类中所有重载版本的同名成员,可以利用作用域显示指定调用
	Son s1;
	s1.func();
	s1.Base::func(10);
}

在这里插入图片描述

继承中的同名静态成员处理

结论和 非静态成员 一致,只不过调用方式有两种

  1. 通过对象
  2. 通过类名,通过类名Son::的方式 访问父类作用域Base::下的m_A静态成员变量(Son::Base::m_A)
class Base
{
public:

	static void func()
	{
		cout << "Base中的func调用 " << endl;
	}

	static void func(int a)
	{
		cout << "Base中的func(int a)调用 " << endl;
	}

	static int m_A;

};

int Base::m_A = 10;


class Son :public Base
{
public:

	static void func()
	{
		cout << "Son中的func调用 " << endl;
	}

	static int m_A;
};
int Son::m_A = 20;

void test01()
{
	//1、通过对象访问
	Son s;
	cout << "m_A = " << s.m_A << endl;
	cout << "Base中的m_A = " << s.Base::m_A << endl;

	//2、通过类名访问
	cout << "m_A = " << Son::m_A << endl;
	//直接通过父类名m_A静态成员变量
	cout << "Base中的m_A = " << Base::m_A << endl;
	//通过子类名的方式 访问父类作用域下的m_A静态成员变量
	cout << "Base中的m_A = " << Son::Base::m_A << endl;
}

void test02()
{
	//1、通过对象
	Son s;
	s.func();
	s.Base::func();


	//2、通过类名
	Son::func();
	Base::func(1);
	//当子类重定义父类中同名成员函数,子类的成员函数会隐藏掉父类中所有版本,需要加作用域调用
	Son::Base::func(1);
}

多继承基本语法

  • class 子类名 : 继承方式 父类1 , 继承方式 父类2
  • 当多继承的两个父类中有同名成员,需要加作用域区分

class Base1
{
public:
	Base1()
	{
		this->m_A = 10;
	}
	int m_A;
};

class Base2
{
public:
	Base2()
	{
		this->m_A = 20;
	}
	int m_A;
};

//多继承
class Son : public Base1, public Base2
{
public:

	int m_C;
	int m_D;
};

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

	Son s;
	//当多继承的两个父类中有同名成员,需要加作用域区分
	cout << s.Base1::m_A << endl;
	cout << s.Base2::m_A << endl;
}

菱形继承

两个类有公共的父类 和共同的子类 ,发生菱形继承
在这里插入图片描述

  • 菱形继承导致数据有两份,浪费资源
    在这里插入图片描述

  • 解决方案:利用虚继承可以解决菱形继承问题


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

//Animal称为 虚基类

//羊类
class Sheep : virtual public Animal{};
//驼类
class Tuo : virtual public Animal{};

//羊驼
class SheepTuo : public Sheep, public Tuo
{
};


void test01()
{
	SheepTuo st;

	st.Sheep::m_Age = 10;
	st.Tuo::m_Age = 20;

	cout << "Sheep::m_Age = " << st.Sheep::m_Age << endl;
	cout << "Tuo::m_Age = " << st.Tuo::m_Age << endl;
	cout << "age = " << st.m_Age << endl;

	//当发生虚继承后,sheep和tuo类中 继承了一个  vbptr指针   虚基类指针   指向的是一个 虚基类表  vbtable
	//虚基类表中记录了  偏移量 ,通过偏移量 可以找到唯一的一个m_Age
}


void test02()
{
	SheepTuo st;
	st.m_Age = 10;

	//通过Sheep找到 偏移量
	//&st 获取首地址
	//(int *)&st 转化步长
	//*(int *)&st 解引用到了 虚基类表base class Sheep中
	//(int *)(*(int *)&st) 强转步长
	//((int *)(*(int *)&st)) + 1  向下偏移1位
	//*(((int *)(*(int *)&st)) + 1)  解引用其偏移值
	int offset = *(((int*)(*(int*)&st)) + 1);
	cout << offset << endl;

	//通过Tuo 找到偏移量
	//(int *)&st转化步长
	//(int *)&st + 1偏移一位
	//*((int *)&st + 1)解引用到虚基类表SheepTuo::$vbtable@Sheep@:中
	//(int *)(*((int *)&st + 1))转化步长
	//(int *)(*((int *)&st + 1)) + 1偏移一位
	//*((int *)(*((int *)&st + 1)) + 1)解引用出偏移值
	cout << *((int*)*((int*)&st + 1) + 1) << endl;

	//通过偏移量  访问m_Age

	cout << "m_Age = " << ((Animal*)((char*)&st + offset))->m_Age << endl;

	cout << "m_Age = " << *((int*)((char*)&st + offset)) << endl;
}
  1. class Sheep : virtual public Animal{};
  2. 当发生虚继承后,sheeptuo类中 继承了一个 vbptr指针 虚基类(base class Sheep , base class Tuo)指针 指向的是一个 虚基类表 vbtable
  3. 虚基类表中记录了 偏移量 ,通过偏移量 可以找到唯一的一个m_Age
  4. 利用地址偏移找到 vbtable中的偏移量 并且访问数据
    在这里插入图片描述
    ((char*)&st + offset)移动到virtual base Animal在这里插入图片描述
    ((Animal*)((char*)&st + offset))->m_Age取出m_Age的值

cout << "m_Age = " << *((int*)((char*)&st + offset)) << endl;直接展开Animal,获取int类型的m_Age

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-02 10:37:50  更:2021-08-02 10:39:52 
 
开发: 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年5日历 -2024/5/9 13:26:14-

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