C++学习笔记之继承

教我们这些凡人贪恋一生的,不正是眼前这些渺小的幸福嘛


封装、多态、继承是面向对象的三大特性。

继承

继承可以减少重复代码,继承后子类中成员包含两部分:自己增加的成员和继承的成员。

语法 : 基类(父类):继承方式  派生类(子类)

继承方式 有三种公有继承、保护继承、私有继承。

#include <iostream>
using namespace std;
class Base
{
public:
	int m_size1;
protected:
	int m_size2;
private:
	int m_size3;
};
class Son1:public Base//公共继承
{
public:
	void fuc()
	{
		m_size1 = 10;//公共继承后,在Son1子类中,m_size1为公共权限
		m_size2 = 20;//公共继承后,在Son1子类中,m_size2为保护权限
		//m_size3 = 0;//m_size3为Base类中的私有私有成员,子类不可访问
	}
	
};
class Son2 :protected Base//保护继承
{
public:
	void fuc()
	{
		m_size1 = 10;//保护继承后,在Son2子类中,m_size1为保护权限
		m_size2 = 20;//保护继承后,在Son2子类中,m_size2为保护权限
		//m_size3 = 0;//m_size3为Base类中的私有私有成员,子类不可访问

	}
};
class Son3 :private Base//私有继承
{
public:
	void fuc()
	{
		m_size1 = 10;//私有继承后,在Son3子类中,m_size1为私有权限
		m_size2 = 20;//私有继承后,在Son3子类中,m_size2为私有权限
		//m_size3 = 0;//m_size3为Base类中的私有私有成员,子类不可访问

	}
};
class GrandSon :public Son3
{
public:
	void fuc()
	{
		//m_size1 = 10;//父类Son3的私有成员,子类不可访问
	}
};

void test1()
{
	Son1 son1;
	son1.m_size1;
	//son2.m_size2;//保护权限类外不可访问
}
void test2()
{
	Son2 son2;
	//son2.m_size1;//保护权限类外不可访问
	//son2.m_size2;//保护权限类外不可访问
}
int main()
{
	test1();
	test2();
	system("pause");
	return 0;
}

继承中的对象模型

父类中所有的非静态成员属性都会被子类继承,编译器会隐藏父类中的私有成员属性,因此子类无法访问,实际上子类仍然继承了这一部分。

#include <iostream>
using namespace std;
class Base
{
public:
	int m_size1;
protected:
	int m_size2;
private:
	int m_size3;
};
class Son :public Base
{
public:
	int m_size4;
};
void test()
{
	cout << "Son类在内存中占"<<sizeof(Son)<<"字节" << endl;//继承12字节加上自己特有的4字节,共计16字节
	
}
int main()
{
	test();
	system("pause");
	return 0;
}

打开开发人员命令提示工具查看对象的内存占用情况:

1.进入文件所在的目录 cd 绝对路径(如果不在C盘下,先跳转盘符 F:(跳转F盘))

2.然后输入  cl /d1 reportSingleClassLayout查看的类名 所属文件名

继承中构造和析构顺序

继承中的构造和析构顺序:先构造父类,再构造子类,先析构子类,再析构父类

继承中同名的成员处理

当子类跟父类拥有同名的成员函数或者属性时,子类会隐藏父类中所有版本的同名函数(包括返回值和参数不同的同名函数)。

子类中的成员属性和函数直接访问即可。

对于一般的成员属性和成员函数,通过添加作用域的方式来访问父类的同名成员属性或者函数。

对于静态的成员属性和成员函数,除了通过作用域的方式之外,还可以通过类名的方式访问。

#include <iostream>
using namespace std;
class Base
{
public:
	int m_size1=10;
	static int m_size2;//静态成员属性类内声明
	void fuc_1()
	{
		cout << "Base类的fuc_1函数" << endl;
	}
	void fuc_1(int a)
	{
		cout << "Base类的传参fuc_1函数" << endl;
	}

	static void fuc_2()
	{
		cout << "Base类的静态fuc_2函数" << endl;;
	};
};
 int Base::m_size2 = 20;//静态成员属性类外定义
 
class Son :public Base
{
public:
	int m_size1=30;
	static int m_size2; //静态成员属性类内声明
	void fuc_1()
	{
		cout << "son类的fuc_1函数" << endl;
	}
	static void fuc_2()
	{
		cout << "son类的静态fuc_2函数" << endl;;
	};
};
int Son::m_size2 = 40; //静态成员属性类内定义
void test()
{
	Son son;
	cout << "son中m_size1为" << son.m_size1 << endl;//直接访问子类自身的同名属性
	cout << "son的继承的父类m_size1为" << son.Base::m_size1 << endl;//
	cout << "son的继承的父类静态父类m_size2为" << Son::Base::m_size2 << endl;//通过类名访问父类中静态同名属性
	cout << "son中静态成员属性m_size2为" << son.m_size2 << endl;//直接访问子类自身的静态同名属性
	cout << "son中继承的父类静态成员属性m_size2为" << son.Base::m_size2 << endl;//通过添加作用域访问父类的静态同名成员属性
	son.fuc_1();//直接访问子类自身的同名函数
	son.fuc_2();//直接访问子类自身的静态同名函数
	son.Base::fuc_1(); //通过添加作用域访问父类的同名成员函数
	son.Base::fuc_1(10);//通过添加作用域访问父类的有参同名成员函数
	son.Base::fuc_2();//通过添加作用域访问父类的静态同名成员函数
	Son::Base::fuc_2();//通过类名访问父类中静态同名函数
}
int main()
{
	test();
	system("pause");
	return 0;
}

多继承语法

多继承语法: class 子类:继承类型 父类1,继承类型 父类2.

实际开发中不建议使用。

#include <iostream>
using namespace std;
class Base1
{
public:
	int m1=10;
	int m2=20;
};
class Base2
{
public:
	int m1=11;
	int m3=30;
};
class Son :public Base1, public Base2//Son多继承的两个父类Base1、Base2
{
public:
	int m4=40;
};
void test()
{
	Son son;
	//添加作用域以区分多继承中父类的同名属性
	cout << "打印父类Base1中的m1的值" << son.Base1::m1 << endl;
	cout << "打印父类Base2中的m2的值" << son.Base2::m1 << endl;
}
int main()
{
	test();
	system("pause");
	return 0;
}

菱形继承

两个子类Base1、Base2继承了同一个父类Base0,又有一个类Son同时继承了这两个子类Base1、Base2,这种继承关系叫做菱形继承(钻石继承)。

菱形继承会出现一个问题,最底层的子类Son中会有两份最上层父类Base0的数据,通过虚继承的方式解决该问题。

#include <iostream>
using namespace std;
class Base0
{
public:
	int m1=1;
};
class Base1:virtual public Base0//继承前加virtual关键字后,变为虚继承,此时公共的父类Animal称为虚基类
{
public:
	int m2=2;
};
class Base2 :virtual public Base0//继承前加virtual关键字后,变为虚继承,此时公共的父类Animal称为虚基类
{
public:
	int m3=3;
};
class Son :public Base1, public Base2//Son多继承的两个父类Base1、Base2
{
public:
	int m4=4;
};
void test()
{
	Son son;
	cout << "打印Son中的m1的值" << son.m1 << endl;
}
int main()
{
	test();
	system("pause");
	return 0;
}

使用虚继承前后son对象占用内存对比如下:

其中,vbptr是虚基指针,vbtable是虚基类表,虚基指针指向虚基类表。

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值