C++进阶学习---继承

继承

继承语法

class 子类名:继承方式1 基类1,继承方式2 基类2{}
继承方式
公有继承:public
保护继承:protected
私有继承:private
继承方式基类public成员基类protected成员基类private成员
publicpublicprotectedprivate
protectedprotectedprotectedprivate
privateprivateprivateprivate

这张表格里面公有继承,基类的访问控制权限不变;保护继承,基类的访问控制权限最低为protected;私有继承,基类的访问控制权限全部为private.

公有继承特点
  • 子类可以直接访问基类的所有公有和保护成员,其效果如同它们是在子类中声明一样
  • 对于基类的私有成员,在子类中存在但不能访问
  • 在子类中定义基类中同名的公有成员或保护成员,子类中的成员会隐藏基类同名成员,想访问被隐藏的成员,可以借助作用域限定符“::”
  • 子类对象任何时候都可以被当成基类类型对象(皆然性 ISA)
保护继承特点
  • 使基类公有成员和保护成员进行保护化,只禁止外部通过该子类访问
  • 子类指针或引用不能隐式转换成基类类型指针或引用
私有继承特点
  • 将基类公有和保护成员私有化,禁止外部通过该子类访问,也禁止该子类的子类访问
  • 子类指针或引用不能隐式转换成基类类型指针或引用
访问控制权限
访问控制限定符访问控制属性基类子类外部友元
public公有成员OKOKOKOK
protected保护成员OKOKNOOK
private私有成员OKNONOOK
  • 不写继承方式,默认私有继承
  • 继承方式是用来指明基类成员在派生类中的最高访问权限的
  • 使用 using关键字可以改变基类公有和保护成员在派生类中的访问权限
继承演示
#include <string>
#include <iostream>
using namespace std;
class Human
{
public:
	Human()
	{
		cout << "Human  构造:" << this << endl;
	}
	void sleep(){
		cout << "基类 Sleep" << endl;
	}
private:
	int m_age;
protected:
	string m_name;
public:
	bool m_gender;  //0 女  1 男
	int m_show;
};  //基类 父类

class Student : public Human
{
public:
	Student() : m_id(0)
	{
		/*
		*	1.派生类可以直接访问基类的所有公有和保护成员,其效果如同它们是在派生类中声明一样
		*/

		//基类中的保护成员在派生类中可以访问
		m_name = "梦凡";
		//基类中的公有成员在派生类中可以访问
		m_gender = 1;

		/*
		*	2.对于基类的私有成员,在派生类中存在但不能访问
		*/
		//m_age = 10;
	}
	void show()
	{
		//隐藏基类中的m_show变量		基类中的m_show存在,用作用域限定符访问
		cout << "派生类中的 m_show:" << m_show <<" "<< "基类中的m_show:" << Human::m_show << endl;
	}
private:
	int m_id;
public:
	//	3.同名隐藏  派生类中定义基类中同名的公有成员或保护成员(成员包括成员变量和成员函数)
	int m_show;		//隐藏基类中的m_show变量		基类中的m_show存在,用作用域限定符访问
	int sleep;		//隐藏基类中的sleep()函数
};	//派生类 子类

int main()
{
	Student s;
	/*
	*	3.同名隐藏测试
	*/
	//s.sleep("水果");	//会报错 因为派生类中的sleep变量将父类中的sleep函数隐藏了
	s.m_show = 10;			//m_show为派生类中的m_show 
	s.Human::m_show = 20;	//通过作用域访问基类中的m_show
	s.show();

	/*
	*	4.公有继承	派生类对象任何时候都可以被当成基类类型对象
	*				基类对象不能隐式转换成派生类对象
	*/
	//缩小访问范围 安全
	Human h = s;
	h.sleep();		//不报错,因为派生类对象隐式转换成基类对象

	Human* ph = &s;	//基类指针指向派生类对象	ph隐式指向基类部分
	Human& rh = s;	//基类引用指向派生类对象	rh隐式指向基类部分

	cin.get();
	return 0;
}
阻断继承

将基类构造函数设为私有,子类永远无法被实例化对象,实现阻断继承

//阻断继承 将构造函数声明为私有
class parent
{
private:
	parent() {}
};
class son :public parent
{
};
int main()
{
    //son s;	无法实例化对象
}
构造析构顺序
子类构造
  • 子类构造函数会调用基类构造函数,构造子类对象中的基类子对象
  • 子类构造函数没有显示指明基类构造方式,会选择基类的缺省构造函数(无参构造)
  • 子类显示调用基类构造函数可以在初始化表中显示指明构造方式。
  • 构造过程:构造基类子对象-》构造成员变量-》执行构造代码
子类析构
  • 子类析构会调用基类析构
  • 通过基类指针析构子类对象,只会析构子类对象中的基类子对象。可能造成内存泄漏
  • 析构过程:执行析构代码-》析构成员变量-》析构基类子对象
演示
#include <string>
#include <iostream>
using namespace std;
class Human
{
public:
	Human()
	{
		cout << "Human构造 this:" << this << endl;
	}
	Human(int age)
	{
		cout << "Human单参 this:" << this << endl;
	}
private:
	int m_age;
	string m_name;
	int m_gender;  
};  //基类 

class Student : public Human
{
public:
	//默认调用基类无参构造
	//Student() :m_no(0) {
	//	cout << "Student构造 this:" << this << endl;
	//}

	/*
	*	2.通过初始化列表选择基类的构造方式
	*/
	Student(int age) :Human(age), m_no(0)
	{
		std::cout << "Student单参构造 this:" << this << std::endl;
	}
private:
	int m_no;
};

int main()
{
	/*
	*	1.构造顺序	在构造析构里面分析过
	*	为整个对象分配内存
	*	构造基类部分(如果存在基类)
	*	构造成员变量
	*	执行构造函数代码
	*/
	//无参构造
	//Student s1;
	//单参构造
	Student s1(18);
	cin.get();
	return 0;
}
多继承

一个类可以从多个基类继承

多重继承内存布局

子类对象中的基类子对象按照继承表顺序依次构造

#include <iostream>
using namespace std;
class Telephone
{
public:
	Telephone()
	{
		cout << "Telephone构造" << endl;
	}
	void call()
	{
		cout << "打电话" << endl;
	}
	int m_t;
};

class Camera
{
public:
	Camera()
	{
		cout << "Camera构造" << endl;
	}
	void photo()
	{
		cout << "照相" << endl;
	}
	int m_c;
};

class Ipod
{
public:
	Ipod()
	{
		cout << "Ipod构造" << endl;
	}
	void music()
	{
		cout << "听歌" << endl;
	}
	int m_i;
};

//子类对象中的基类子对象按照继承表顺序依次构造
class IphoneXs :public Telephone, public Camera, public Ipod
{
public:
	IphoneXs()
	{
		cout << "IphoneXs构造" << endl;
	}
	int i;
};

int main()
{
	IphoneXs ipx;   //构造一个子类对象
	ipx.call();
	ipx.photo();
	ipx.music();
	cout << "------------------" << endl;

	//基类指针指向子类对象
	Telephone* t = &ipx;  //公有继承 皆然性   子类IS A父类
	Camera* c = &ipx;      //公有继承 皆然性   子类IS A父类
	Ipod* i = &ipx;		  //公有继承 皆然性   子类IS A父类

	cout << t << " " << c << " " << i << endl;
	cin.get();
	return 0;
}
Telephone构造
Camera构造
Ipod构造
IphoneXs构造
打电话
照相
听歌
------------------
006FF754 006FF758 006FF75C
棱形继承

中间子类有公共基类,导致最终子类存在多个公共基类,导致调用歧义通过使用::明确调用

在这里插入图片描述

#include <iostream>
using namespace std;
class A
{
public:
	A()
	{
		cout << "A构造" << this << endl;
	}
	int m_a;
	void foo()
	{
		m_a = 10;
		cout << m_a << endl;
	}
};	

class X :public A
{
public:
	X()
	{
		cout << "X构造" << this << endl;
	}
};

class Y :public A
{
public:
	Y()
	{
		cout << "Y构造" << this << endl;
	}
};

class Z :public X, public Y
{
public:
	Z()
	{
		cout << "Z构造" << this << endl;
	}
};

int main()
{
	Z z;
	//z.foo();   调用不明确   z对象中有X和Y的对象,X和Y中有A的对象  
	//不知道调用X->A.foo 还是调用Y->A.foo();
	z.X::foo();
	z.Y::foo();

	//z.A::foo();
	z.X::A::foo();
	return 0;
}
虚继承

在公共基类继承方式前加关键字virtual

在公共基类对象保存到公共位置,存储偏移值

在这里插入图片描述
虚继承是为了解决棱形继承中成员访问的二义性。在A B继承方式前加关键字virtual,编译器将Base的数据保存在一个公共位置,通过虚基表访问。

#include <iostream>
using namespace std;
class A
{
public:
	A()
	{
		cout << "A构造" << this << endl;
	}
	int m_a;
	int m_b;
	void foo()
	{
		m_a = 10;
		cout << m_a << endl;
	}
};
/*
*	解决方法二:虚继承基类A
*/
class X :virtual public A
{
public:
	X()
	{
		cout << "X构造" << this << endl;
	}
};

class Y :virtual public A
{
public:
	Y()
	{
		cout << "Y构造" << this << endl;
	}
};

class Z :public X, public Y
{
public:
	Z()
	{
		cout << "Z构造" << this << endl;
	}
};

int main()
{
    cout << "A:" << sizeof(A) << ",X:" << sizeof(X) << ",Y:" << sizeof(Y) << ",Z:" << sizeof(Z) << endl;
	Z z;
	//z.foo();	//对“foo”的访问不明确	
	/*
	*	解决方法一:作用域::这么调用哪个父类里面的foo函数
	*/
	//z.X::foo();
	//z.Y::foo();
	z.foo();	//虚继承解决棱形继承问题
	cin.get();
	return 0;
}

A:4,X:8,Y:8,Z:12
A构造00F6F994
X构造00F6F98C
Y构造00F6F990
Z构造00F6F98C
10

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

DeRoy

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

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

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

打赏作者

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

抵扣说明:

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

余额充值