C++57个入门知识点_29 从内存角度看继承(子类继承时包含(复制)了父类所有成员变量,但由于继承的可见性,只可对部分进行访问;运行时可修改父类成员;子类转父类安全,父类转子类不安全(越界访问))

上篇C++57个入门知识点_28 继承的可见性(父类成员在子类中可见性;影响因素:父类内部关键字+继承位置关键字;父亲某属性成员,变为儿子中某种属性成员;编译期检查访问权限,子类对象内存包含父类所有成员)中介绍了继承的可见性即父类成员在子类中可见性。本篇讨论可见性究竟是在什么时候发生的呢?

总结:

1. 内存角度看继承及通过指针修改内存

  • 子类继承时包含(复制)了父类所有的成员变量,但是由于继承的可见性限制,只可以对部分进行访问
  • 继承的可见性是在编译时刻做的限制,本质上可以在运行时通过指针修改

2. 子类转父类是安全的,父类转子类是不安全的(造成越界访问)

1. 内存角度看继承及通过指针修改内存

  • 子类继承时包含(复制)了父类所有的成员变量,但是由于继承的可见性限制,只可以对部分进行访问
  • 继承的可见性是在编译时刻做的限制,本质上可以在运行时通过指针修改

1.1 内存角度看继承

#include <iostream>

class CPerson
{
public:
	CPerson() {
	}
	~CPerson() {
	}

public:
	int m_nPublic;
protected:
	int m_nProtected;
private:
	int m_nPrivate;
};

class CStudent : private CPerson
{
public:
	CStudent() {

	}
	~CStudent() {
	}
private:
	int m_nStuID;
};

int main(int argc, char* argv[])
{
	int nPerSize = sizeof(CPerson);
	int nStudSize = sizeof(CStudent);
    CStudent stu;

	return 0;
}

运行结果:CPerson类中有3个int类型成员变量,其子类中数据成员变量为1个int,从结果看总共16个字节,子类本身的4个字节+CPerson中的12个字节,子类继承了父类中的所有字节
在这里插入图片描述
创建CStudent对象,查看其内存
在这里插入图片描述
从上面的结果可以看到:子类中包含了父类的所有成员,根据上篇所讲由于关键字的控制,父类的成员具有可见性的差异

1.2 通过指针在运行时进行内存修改

#include <iostream>

class CPerson
{
public:
	CPerson() {
	}

	~CPerson() {
	}
public:
	int m_nPublic;
protected:
	int m_nProtected;
private:
	int m_nPrivate;
};

class CStudent : private CPerson
{
public:
	CStudent() {
	}
	~CStudent() {
	}
private:
	int m_nStuID;
};

int main(int argc, char* argv[])
{
	int nPerSize = sizeof(CPerson);
	int nStudSize = sizeof(CStudent);

	CStudent stu;

	//(char*)&stu将地址强转为char*,+ 8指向m_nPrivate
	//(int*)将地址强转为int*,代表了内部存储的数据类型为int型
	int* p = (int*)((char*)&stu + 8);

	//p指向的m_nPrivate内容修改为123;
	*p = 123;

	return 0;
}

运行结果:运行期将m_nPrivate进行修改
在这里插入图片描述

2. 指针转换的安全性

子类转父类是安全的,父类转子类是不安全的(造成越界访问)。

  • 儿子的空间范围要比父亲的多,因此儿子可以通过指针转换为父亲
	CStudent stu;

	//子类指针转换为父类指针(安全),可以说学生都是人
	CPerson* pPer = &stu;

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

  • 父亲的空间范围要比儿子的小,经过强制转换pStu就可以访问不属于per的内容,属于越界访问
    CPerson per;

	//父类指针转换为子类指针(不安全),不能说人都是学生
	CStudent* pStu =(CStudent*)&per;

在这里插入图片描述

3.学习视频地址:C++57个入门知识点_29 从内存角度看继承

4.学习笔记:


#include <iostream>

//面向对象:继承
//继承的可见性在何时做的检查?
//是由编译器在编译时刻做的限制,本质上可以在运行时可以通过指针修改
//继承时父类将所有成员赋给了子类,继承部分指针指向父类的内存
//但是由于可见性问题,只能看到没有做限制的成员

class CPerson 
{

public:
	CPerson() {

	}

	~CPerson() {

	}

	int GetGender() {

		return m_nGender;
	}

	void SetGender(int nGender) {

		m_nGender = nGender;
	}
//父亲公有的都可以访问
public :
	int m_nPublic;

//父亲的家族财产给儿子继承
protected:
	int m_nProtected;

//父亲的私有财产不能给儿子继承
private:

	char m_nszName[255];
	int m_nGender; 


};

//父类的继承也有三种属性
class CStudent :public CPerson
{
public:
	CStudent(){
		m_nPublic = 1;
		m_nProtected = 1;//类域内部可以访问父类的保护成员
	}

	~CStudent() {

	}

private:

	int m_nStuID;
};

//增加老师管理系统,老师的数据与行为和学生是类似的,但也有学号,老师号的不同
//如果重建一个老师类就会造成冗余,易造成错误
class CTeacher :public CPerson
{
public:
	CTeacher() {

	}

	~CTeacher() {

	}

private:

	int m_nTeaID;
};


int main(int argc,char* argv[])
{
	int nPerSize = sizeof(CPerson);

	int nStudent = sizeof(CStudent);

	CPerson per;
	CStudent stu;

	//取stu中 m_nszName[255]:&stu取地址,(char*)&stu强制转换为char*
	//((char*)&stu + 8) m_nszName前有public和protected8字节
	//(int*)((char*)&stu + 8)取地址到p
	int* p = (int*)((char*)&stu + 8);
	//p指向的内容修改为123;
	*p = 123;

	//指针转换的安全性
	//子类指针转换为父类指针(安全),可以说学生都是人
	CPerson* pPer = &stu;

	//父类指针转换为子类指针(不安全),但是不能说人都是学生
	//CStudent* pStu =(CStudent*)&per;

	return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十月旧城

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值