10—C++类和对象—继承

29类—继承(基本语法)

#include<iostream>
using namespace std;
#include<string>
//继承
/*
继承
继承是面向对象三大特性之一
有些类与类之间存在特殊的关系:
例如:动物(猫,狗),猫(加菲猫,汤姆猫),狗(哈士奇,柯基)

我们发现,定义这些类时,下级别的成员除了拥有上一级的共性,还有自己的特性。

这个时候我们就可以考虑利用继承的技术,减少重复代码(继承的原因)

继承的基本语法:(class 子类 : 继承方式 父类)

派生类中的成员,包含两大部分:
一类是从基类继承过来的,一类是自己增加的成员。
从基类继承过过来的表现其共性,而新增的成员体现了其个性。

例如我们看到很多网站中,都有公共的头部,公共的底部,甚至公共的左侧列表,只有中心内容不同,

接下来我们分别利用普通写法和继承的写法来实现,重复利用公共部分,看一下继承存在的意义以及好处
*/

//举例:一个IT网站有很多网页,学习java的网页,学习C++的网页,学习python的网页
//这些网页都有公共的头部,底部,左侧列表
//普通实现
//java页面
class Java01{
public:
	void publicPart(){
		cout << "公共的头部,底部,左侧列表" << endl;
	}
	void privatePart(){
		cout << "Java01页面特有内容" << endl;
	}
};
//C++页面
class Cpp01{
public:
	void publicPart(){
		cout << "公共的头部,底部,左侧列表" << endl;
	}
	void privatePart(){
		cout << "Cpp01页面特有内容" << endl;
	}
};
//python页面
class Python01{
public:
	void publicPart(){
		cout << "公共的头部,底部,左侧列表" << endl;
	}
	void privatePart(){
		cout << "Python01页面特有内容" << endl;
	}
};
void Test01()
{
	Java01 java01;
	java01.privatePart();
	java01.publicPart();
	Cpp01 cpp01;
	cpp01.privatePart();
	cpp01.publicPart();
	Python01 python01;
	python01.privatePart();
	python01.publicPart();
}

//继承实现
//基类
class PublicPart{
public:
	void publicPart(){
		cout << "公共的头部,底部,左侧列表" << endl;
	}
};
//子类
class Java02 : public PublicPart{
public:
	void privatePart(){
		cout << "Java02页面特有内容" << endl;
	}
};
class Cpp02 : public PublicPart{
public:
	void privatePart(){
		cout << "Cpp02页面特有内容" << endl;
	}
};
class Python02 : public PublicPart{
public:
	void privatePart(){
		cout << "Python02页面特有内容" << endl;
	}
};
void Test02()
{
	Java02 java02;
	java02.privatePart();
	java02.publicPart();
	Cpp02 cpp02;
	cpp02.privatePart();
	cpp02.publicPart();
	Python02 python02;
	python02.privatePart();
	python02.publicPart();
}
int main(){
	//Test01();
	Test02();
	system("pause");
	return 0;
}

30类—继承(继承方式)

#include<iostream>
using namespace std;
#include<string>
//继承方式
/*
继承方式一共有三种:
公共继承:public
保护继承:protected
私有继承:private

子类不管用何种方式继承父类,父类中的权限在子类中不能提高(父类中的private属性不可访问)
public方式继承,子类权限和父类权限相同(也可降低为protected和private)
protected方式继承,子类中的权限降低为protected(也可降低为private)
private方式继承,子类权限只能为private

class Father{
public:
	int a;
protected:
	int b;
private:
	int c;
};
class Son01 :public Father{
public:
	int a;
protected:
	int b;
//Father的私有属性不允许访问
};
class Son02 :protected Father{
protected:
	int a;
	int b;
	//Father的私有属性不允许访问
};
class Son03 :private Father{
private:
	int a;
	int b;
	//Father的私有属性不允许访问
};
*/
//验证
class Father
{
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C;
};

//1.公共继承
class Son1 :public Father
{
public:
	void func()
	{
		m_A; //可访问 public权限
		m_B; //可访问 protected权限
		//m_C; //不可访问
	}
};

void myClass()
{
	Son1 s1;
	s1.m_A; //其他类只能访问到公共权限
}

//2.保护继承
class Son2 :protected Father
{
public:
	void func()
	{
		m_A; //可访问 protected权限
		m_B; //可访问 protected权限
		//m_C; //不可访问
	}
};
void myClass2()
{
	Son2 s;
	//s.m_A; //不可访问
}

//3.私有继承
class Son3 :private Father
{
public:
	void func()
	{
		m_A; //可访问 private权限
		m_B; //可访问 private权限
		//m_C; //不可访问
	}
};
void myClass3()
{
	Son3 s;
	//s.m_A; //不可访问
}
class GrandSon3 :public Son3
{
public:
	void func()
	{
		//Son3是私有继承,所以继承Son3的属性在GrandSon3中都无法访问到
		//m_A;
		//m_B;
		//m_C;
	}
};
int main(){
	system("pause");
	return 0;
}

31类—继承(继承中的对象模型)

#include<iostream>
using namespace std;
#include<string>
//继承中的对象模型
/*
从父类继承过来的成员,那些属于子类中
结论: 父类中私有成员也是被子类继承下去了,只是由编译器给隐藏后访问不到

用VS自带的开发人员命令提示工具查看单个类的布局:
第一步:进入存放项目的文件的路径,然后使用命令:dir,查看路径下的所有文件
第二步:cl -d1 reportSingleClassLayout[classname] sourceFile.cpp
例如:cl -d1 reportSingleClassLayoutSon 31类—继承(继承中的对象模型).cpp
结果:(从父类继承过来3个,自己的一个,一共4个int,16个字节)
class Son       size(16):
+---
| +--- (base class Base)
0      | | m_A
4      | | m_B
8      | | m_C
| +---
12      | m_D
+---
*/

class Base
{
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C; //私有成员只是被隐藏了,但是还是会继承下去
};
//公共继承
class Son :public Base
{
public:
	int m_D;
};

void test01()
{
	//结果为16,说明Son中有四个整形变量,从父类继承过来三个,自己创建一个
	cout << "sizeof Son = " << sizeof(Son) << endl;//结果为16
	Son s1;
	s1.m_A = 10;//从父类继承过来的,父类中为public权限,可以访问
	//s1.m_B = 10;//从父类继承过来的,父类中为protected权限,不可以访问
	//s1.m_C=10;//从父类继承过来的,父类中为private权限,不可以访问
	s1.m_D = 10;
}

int main() {
	test01();
	system("pause");
	return 0;
}

32类—继承(继承中构造和析构顺序)

#include<iostream>
using namespace std;
#include<string>
//继承中构造和析构顺序
/*
子类继承父类后,当创建子类对象,也会调用父类的构造函数
问题:父类和子类的构造和析构顺序是谁先谁后?
结论:继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反
*/

class Base
{
public:
	Base()
	{
		cout << "Base构造函数!" << endl;
	}
	~Base()
	{
		cout << "Base析构函数!" << endl;
	}
};

class Son : public Base
{
public:
	Son()
	{
		cout << "Son构造函数!" << endl;
	}
	~Son()
	{
		cout << "Son析构函数!" << endl;
	}

};

void test01()
{
	//继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反
	Son s;
}

int main() {
	test01();
	system("pause");
	return 0;
}

33.类—继承(继承同名成员处理方式)

#include<iostream>
using namespace std;
#include<string>
//继承同名成员处理方式
/*
成员:成员函数,成员变量
问题:当子类与父类出现同名的成员,如何通过子类对象,访问到子类或父类中同名的数据呢?

结论:
1. 子类对象可以直接访问到子类中同名成员
2. 子类对象加作用域可以访问到父类同名成员
3. 当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数

访问子类同名成员 直接访问即可
访问父类同名成员 需要加作用域
*/
class Base {
public:
	Base()
	{
		m_A = 100;
	}

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

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

public:
	int m_A;
};

class Son : public Base {
public:
	Son()
	{
		m_A = 200;
	}

	//当子类与父类拥有同名的成员函数,子类会隐藏父类中所有版本的同名成员函数
	//如果想访问父类中被隐藏的同名成员函数,需要加父类的作用域
	void func()
	{
		cout << "Son - func()调用" << endl;
	}
public:
	int m_A;
};

void test01()
{
	Son s;

	cout << "Son下的m_A = " << s.m_A << endl;
	cout << "Base下的m_A = " << s.Base::m_A << endl;

	s.func();
	s.Base::func();
	s.Base::func(10);//调用父类中的有参构造
}
int main() {
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

34类—继承(继承同名静态成员处理方式)

#include<iostream>
using namespace std;
#include<string>
//继承同名静态成员处理方式
/*
问题:继承中同名的静态成员在子类对象上如何进行访问?
结论:同名静态成员处理方式和非静态处理方式一样,只不过有两种访问的方式(通过对象 和 通过类名)

因为静态成员函数和成员变量,所有对象共享,所以可以通过类名访问:Son::Base::func();

静态成员和非静态成员出现同名,处理方式一致
访问子类同名成员   直接访问即可
访问父类同名成员   需要加作用域


*/
class Base {
public:
	static void func()
	{
		cout << "Base - static void func()" << endl;
	}
	static void func(int a)
	{
		cout << "Base - static void func(int a)" << endl;
	}

	static int m_A;//静态成员变量,类内定义
};

int Base::m_A = 100;//静态成员变量,类外初始化

class Son : public Base {
public:
	static void func()
	{
		cout << "Son - static void func()" << endl;
	}
	static int m_A;
};

int Son::m_A = 200;

//同名成员属性
void test01()
{
	//通过对象访问
	cout << "通过对象访问: " << endl;
	Son s;
	cout << "Son  下 m_A = " << s.m_A << endl;
	cout << "Base 下 m_A = " << s.Base::m_A << endl;

	//通过类名访问
	cout << "通过类名访问: " << endl;
	cout << "Son  下 m_A = " << Son::m_A << endl;
	//第一个双冒号代表通过类名方式访问,第二个双冒号代表访问父类作用域下
	cout << "Base 下 m_A = " << Son::Base::m_A << endl;
}

//同名成员函数
void test02()
{
	//通过对象访问
	cout << "通过对象访问: " << endl;
	Son s;
	s.func();
	s.Base::func();
	cout << "通过类名访问: " << endl;
	Son::func();
	Son::Base::func();
	//出现同名,子类会隐藏掉父类中所有同名成员函数,需要加作作用域访问
	Son::Base::func(100);//访问父类中的有参构造
}
int main() {
	//test01();
	test02();
	system("pause");
	return 0;
}

35类—继承(多继承语法)

#include<iostream>
using namespace std;
#include<string>
//多继承语法(一个儿子多个爸爸)
/*
C++允许,一个类继承多个类

语法:class 子类 :继承方式 父类1 , 继承方式 父类2...

多继承可能会引发父类中有同名成员出现,需要加作用域区分

总结: 多继承中如果父类中出现了同名情况,子类使用时候要加作用域

C++实际开发中不建议用多继承
*/
class Base1 {
public:
	Base1()
	{
		m_A = 100;
	}
public:
	int m_A;
};

class Base2 {
public:
	Base2()
	{
		m_A = 200;  //开始是m_B 不会出问题,但是改为mA就会出现不明确
	}
public:
	int m_A;
};

//语法:class 子类:继承方式 父类1 ,继承方式 父类2 
class Son : public Base2, public Base1
{
public:
	Son()
	{
		m_C = 300;
		m_D = 400;
	}
public:
	int m_C;
	int m_D;
};

//多继承容易产生成员同名的情况
//通过使用类名作用域可以区分调用哪一个基类的成员
void test01()
{
	Son s;
	cout << "sizeof Son = " << sizeof(s) << endl;
	cout << s.Base1::m_A << endl;
	cout << s.Base2::m_A << endl;
}

int main() {
	test01();
	system("pause");
	return 0;
}

36类—继承(菱形继承)

#include<iostream>
using namespace std;
#include<string>
//菱形继承
/*
菱形继承概念:(顾名思义,继承关系像个菱形)
两个派生类继承同一个基类
又有某个类同时继承者两个派生类
​这种继承被称为菱形继承,或者钻石继承

例如:狗继承动物,熊继承动物,狗熊继承狗和熊(C++中允许多继承)

菱形继承带来的问题:子类继承两份相同的数据(因为狗和熊都继承自动物),导致资源浪费以及毫无意义

利用虚继承可以解决菱形继承问题
可以通过31讲中的方法:用VS自带的开发人员命令提示工具查看单个类的布局,看一看虚继承底层实现原理
(创建两个虚基类指针vbptr,通过偏移量的增加,指向同一个地址)

不建议使用这种继承方式
*/
class Animal
{
public:
	int m_Age;
};

//继承前加virtual关键字后,变为虚继承
//此时公共的父类Animal称为虚基类,virtual
class Dog :virtual public Animal {};
class Bear :virtual public Animal {};
//可以通过31讲中的方法:用VS自带的开发人员命令提示工具查看单个类的布局
//把virtual关键字去掉,看一看
class DogBear : public Dog, public Bear {};
void test01()
{
	DogBear db;
	db.Dog::m_Age = 100;
	db.Bear::m_Age = 200;
	//使用虚继承之后,赋值会被覆盖(就不会产生二义性了)
	cout << "db.Dog::m_Age = " << db.Dog::m_Age << endl;
	cout << "db.Bear::m_Age = " << db.Bear::m_Age << endl;
	cout << "db.m_Age = " << db.m_Age << endl;
}

int main() {
	test01();
	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

彤彤的小跟班

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

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

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

打赏作者

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

抵扣说明:

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

余额充值