C++学习之继承

继承

子类也称为派生类,父类也称为基类

语法

class 子类:继承方式 父类
公共继承、保护继承、私有继承
父类的private成员无论用哪种继承,子类都不可以访问
公共继承:父类中是公共属性的,子类继承后也是公共的;父类中是保护属性的,子类继承后仍是保护属性的。
保护继承:父类中公共和保护属性的,子类继承后均为保护权限。
私有继承:父类中公共和保护属性的,子类继承后均为私有权限。

继承中的对象模型

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

#include<iostream>
#include<string>
using namespace std;

class Base1
{
public:
	int m_a;
protected:
	int m_b;
private:
	int m_c;
};
class Base2
{
public:
	double m_a;
protected:
	double m_b;
private:
	double m_c;
};
class Son1 :public Base1
{
	int m_d;
};
class Son2 : private Base2
{
	int m_d;
};

void test()
{
	Son1 s1;
	Son2 s2;
	cout << "s1的大小" << sizeof(s1) << endl;
	cout << "s2的大小" << sizeof(s2) << endl;
}
int main()
{
	test();
	system("pause");
}

在这里插入图片描述

我试了一下,s1的16包括父类的三个整型数据加子类中一个整型数据
而s2的32我不太明白,父类中三个double是24,子类中有个整型不应该是24+4=28吗。
深入检查:
利用开发人员命令提示工具查看对象模型:
开始----visual studio 文件夹里有个开发人员命令提示工具
跳转盘符: F:(我是F盘)–>跳转文件路径:cd 具体路径–>查看目录:dir–>命令行:
cl /d1 reportSingleClassLayout类名 文件名
第一个l是L的小写,第二个1是数字1,文件名可以手打也可以通过Tab键选择。
回车后:
在这里插入图片描述
但看这个也是24+4=28,不太明白

继承中构造和析构顺序

class Base1
{
public:
	int m_a;
protected:
	int m_b;
private:
	int m_c;
public:
	Base1()
	{
		cout << "Base1的构造" << endl;
	}
	~Base1()
	{
		cout << "Base1的析构" << endl;
	}
};

class Son1 :public Base1
{
public:
	int m_d;
	Son1()
	{
		cout << "Son1的构造" << endl;
	}
	~Son1()
	{
		cout << "Son1的析构" << endl;
	}
};
void test()
{
	Son1 s1;
}

在这里插入图片描述
可以看出,父类先构造,子类后构造
子类先析构,父类后析构。

继承中同名成员处理方式

当子类与父类出现同名成员时:
访问子类同名成员,直接访问即可
访问父类同名成员,需要加作用域。

class Base
{
public:
	string m_a;
	Base()
	{
		m_a = "父类";
	}
};

class Son :public Base
{
public:
	string m_a;
	Son()
	{
		m_a = "子类";
	}
	void func()
	{
		cout << m_a << endl
			<< Base::m_a << endl;
	}
};
void test()
{
	Son s1;
	s1.func();
	cout << s1.m_a<<endl
		<<s1.Base::m_a<<endl;
}

在这里插入图片描述
遇到同名成员函数也一样,
遇到子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数,想访问父类的同名函数就要加作用域。

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

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

class Base
{
public:
	static string m_a;
};
string Base::m_a = "父类";
class Son :public Base
{
public:
	static string m_a;
};
string Son::m_a = "子类";
void test()
{
	Son s1;
	cout << "通过对象访问:"<<endl
		 << s1.m_a<< endl
		 << s1.Base::m_a <<endl
		 << "通过类名访问:"<<endl
		 << Base::m_a <<endl 
		 << Son::m_a <<endl
		 << Son::Base::m_a << endl ;
}

在这里插入图片描述

多继承语法

允许一个类继承多个类
class 子类:继承方式 父类1,继承方式 父类2.。。
遇到同名成员时,要加作用域。

菱形继承(钻石继承)

两个派生类A、B继承同一个基类O,又有某个类C同时继承两个派生类。
可能会出现二义性:
A、B中都继承有O的属性,C访问该数据时,会出现二义性,可以加作用域解决,其次某项属性C会继承两份,利用虚继承。
在继承最大的基类时加上virtual变为虚继承,最大的基类变成虚基类


class Base
{
public:
	int m_age;
};
class Son1 :public Base{};
class Son2 : public Base{};
class Grandson :public Son1, public Son2{};
void test()
{
	Grandson g1;
	g1.Son1::m_age = 1;
	g1.Son2::m_age = 2;

	cout << "g1.Son1::m_age =" << g1.Son1::m_age << endl
		<< "g1.Son2::m_age =" << g1.Son2::m_age << endl;
}

在这里插入图片描述
使用开发者命令行工具
在这里插入图片描述
可以看到继承了两个m_age
解决方法:虚继承

class Son1 :virtual public Base{};
class Son2 :virtual public Base{};

在这里插入图片描述
利用开发者命令行工具
在这里插入图片描述
从Son1和Son2继承下的是(vbptr)虚基类指针
指向的是vbtable:虚基类表,从上图中vbtable中的8和4是偏移量,继承Son1时就是0(起始)+8(偏移量)=8,继承Son2时就是4(起始)+4(偏移量)=8
起始值从左边那列看

  • 12
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值