继承的基本概念+用法

继承的基本语法

继承的好处:可以减少大量的重复代码(eg:某几个页面中重复的内容就可以用继承减少每页的代码量)

继承的语法:class A:继承方式(eg:public) B{};---A称为子类(也称为派生类)、B称为父类(也称为基类)

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

#include
using namespace std;
//创建一个基类
class base {
public:
	void header()
	{
		cout << "页面头部包含首页、会员中心、视频、题库等(公共顶部)" << endl;
	}
	void rear()
	{
		cout << "页面尾部包含帮助中心、交流合作、站内地图等(公共底部)" << endl;
	}
	void left()
	{
		cout << "页面的左边有java、python、C++等(公共分类列表)" << endl;
	}
};
//创建子类
//若不使用继承,则每个子类中都需要额外再添加基类中的三个函数代码,大大增加了重复的代码量
class java :public base {
public:
	void content()//内容函数
	{
		cout << "此为java页面独有的内容" << endl;
	}
};
class python :public base {
public:
	void content()
	{
		cout << "此为python页面独有的内容" << endl;
	}
};
class cpp :public base {
public:
	void content()//内容
	{
		cout << "此为C++页面独有的内容" << endl;
	}
};
void test01()
{
//打印输出页面中的内容
	java ja;
	ja.header();
	ja.rear();
	ja.left();
	ja.content();
	cout << "-------------------------------" << endl;
	python py;
	py.header();
	py.rear();
	py.left();
	py.content();
	cout << "-------------------------------" << endl;
	cpp c;
	c.header();
	c.rear();
	c.left();
	c.content();
}
int main()
{
	test01();
	system("pause");
	return 0;
}

继承方式

继承方式有三种(分别对应三种权限):公有继承(public)、保护继承(protected)、隐私继承(private)

继承的基本概念+用法_第1张图片

公有继承

父类的隐私属性,子类仍然不可访问(子类内类外都不可访问)。父类的保护属性,子类中继承的仍然是保护属性(子类内可访问,类外不可访问)。父类中的公共属性,子类中仍然是公有属性(类内类外都可访问)

保护继承

父类的隐私属性,子类仍然不可访问(类内类外都不可访问)。父类的保护属性和公有属性到子类都变成了保护属性(子类内可访问,类外不可访问)

私有继承

父类的一切属性到类内都变成了私有属性。父类中私有属性,子类仍不能访问。父类中的其他属性,子类中类内可以访问,类外不能访问

继承中的对象模型

即研究子类中是否全部继承或部分继承父类中的属性

#include
using namespace std;
//创建父类
class base1 {
public:
	int m_a;
protected:
	int m_b;
private:
	int m_c;
};
//创建子类
class son:public base1 {
public:
	int m_d;
};
void test01()
{
	//对象实例化
	son s;
	cout << sizeof(s) << endl;
	//打印结果为16,说明父类中所有非静态成员属性都会被子类继承下去(不管公有还是私有)
	//注:父类中私有成员属性访问不到,是因为被编译器隐藏了,但是父类的私有成员属性仍然会被子类继承
}
int main()
{
	test01();
	system("pause");
	return 0;
}

继承中的构造函数和析构函数执行顺序

即先执行父类的构造函数,还是先执行子类构造函数的问题

结论:先执行父类的构造函数,再执行子类的构造函数。析构函数执行顺序与构造函数相反(构造函数先执行完,再执行析构函数)

#include
using namespace std;
//验证:
class father {
public:
	father()
	{
		cout << "父类的构造函数" << endl;
	}
	~father()
	{
		cout << "父类的析构函数" << endl;
	}
};
class son: public father {
public:
	son()
	{
		cout << "子类的构造函数" << endl;
	}
	~son()
	{
		cout << "子类的析构函数" << endl;
	}
};
void test01()
{
	son s;
}



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

继承中同名成员处理

结论:访问子类同名成员(属性/函数),直接访问即可。访问父类同名成员,需要加作用域(父类(eg:base)::)

#include
using namespace std;
//父类
class base {
public:
	int m_a=100;
	void func()
	{
		cout << "此为父类的func()成员函数" << endl;
	}
	void func(int)//int为占位符,占用一字节,作用为区分重载后的func函数
	{
		cout << "此为base类的func(int)成员函数" << endl;
	}
};
//子类
class son:public base {
public:
	int m_a = 200;//与父类中同名成员属性
	void func()//与父类中同名的成员函数
	{
		cout << "此为子类的func()成员函数" << endl;
	}
};

void test01()
{
	son s;//子类对象实例化
	cout << s.m_a << endl;//输出结果为200,即子类中的m_a的值
	cout << s.base::m_a << endl;//输出结果为100,即父类中的m_a的值
	s.func();//调用的是子类的func函数
	s.base::func();//加了作用域后,调用父类的func函数。
	//s.func(10);函数报错。原因是因为子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数。
	//如果想访问到父类中被隐藏的同名成员函数,需要加作用域。
	s.base::func(100);//调用父类的func(int)函数
}
int main()
{
	test01();
	system("pause");
	return 0;
}

同名静态成员处理

处理方法总结:与同名非静态成员处理基本一致。访问子类同名成员(属性/函数),直接访问即可。访问父类同名成员,需要加作用域(父类(eg:base)::)

静态成员特征:静态成员在内存中共享一份数据、在编译阶段分配内存、静态成员属性类内声明,类外初始化

区别:静态成员有两种调用方式

示例:

#include
using namespace std;
//创建父类
class base {
public:
	static int m_a;
	static void func()
	{
		cout << "此为父类func()静态函数" << endl;
	}
	static void func(int)//int为占位符
	{
		cout << "此为父类func(int)静态函数" << endl;
	}
};
int base:: m_a=100;
//创建子类
class son:public base {
public:
	static int m_a;
	static void func()
	{
		cout << "此为子类静态函数" << endl;
	}
};
int son::m_a = 200;//类外初始化
void test01()
{
	//通过对象访问
	cout << "通过对象访问对象属性" << endl;
	son s;
	cout << s.m_a << endl;//输出结果为200(子类)
	cout << s.base::m_a << endl;//输出结果为100
	//通过类名访问
	cout << "通过对象访问对象属性" << endl;
	cout << son::m_a << endl;
	//第一个::表示通过类名方式访问,第二个::代表在父类的作用域下访问
	cout << son::base::m_a << endl;//(输出父类的结果)

}
void test02()
{
	//通过对象访问成员函数
	cout << "通过对象访问对象函数:" << endl;
	son s;
	s.func();//访问子类的func函数
	s.base::func();//访问父类的func函数
	//通过类名访问成员函数
	cout << "通过对象访问对象函数:" << endl;
	son::func();
	//第一个::表示通过类名方式访问,第二个::代表在父类的作用域下访问
	son::base::func();
	//son::func(100);编译器报错,因为子类出现和父类同名的静态成员函数,同样会隐藏父类中所有同名成员函数
	//如果想访问父类中被隐藏的同名成员,需要加作用域
}
int main()
{
	//test01();
	test02();
	system("pause");
	return 0;
}

多继承语法

C++中允许一个类继承多个类(即一个子类可以继承多个父类)

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

多继承中如果父类中出现同名的情况,子类使用时要加作用域,因此C++实际开发中不建议用多继承

菱形继承


概念:

两个派生类(子类)继承同一个基类(父类),又有某个类(孙子类)同时继承这两个派生类(子类)。这种继承方式称为菱形继承或钻石继承

图示:

继承的基本概念+用法_第2张图片

菱形继承所带来的问题

菱形继承中子类会继承两份相同的的数据,导致资源的浪费。

由于多继承的原因,子类会继承父类的数据,而若多个父类中有相同的数据A,则会造成子类成员属性访问的二义性,且毫无意义(即原本子类中只需要一份数据A即可)

解决方案

利用虚继承可以解决菱形继承问题

即:

#include
using namespace std;
class father {
public:
	int age;
};
//不采用虚继承的方式继承两个父类
//class base1:public father{};
//class base2 :public father{};


//采用虚继承的方式继承两个父类
//在继承方式前加virtual关键字后,变成虚继承
class base1 :virtual public father {};
class base2 :virtual public father {};
class son :public base1, public base2 {};//用公共继承方式继承base1和base2
//采用虚继承的方式继承两个父类

void test01()
{
	son s;
	s.base1::age = 100;
	s.base2::age = 200;
	//未采用虚继承方式前
	//s.age;//编译器报错,因为编译器不清楚要访问的是base1的age还是base2的age 
	cout << s.base1::age << endl;//打印base1中的age
	cout << s.base2::age << endl;//打印base2中的age
	//若子类中只需要一份age数据,则可以通过虚继承来实现
	//采用虚继承方式后
	//打印结果都为200
	s.age;
	cout << s.age << endl;
	cout << s.base1::age << endl;
	cout << s.base2::age << endl;
}
int main()
{
	test01();
	system("pause");
	return 0;
}

你可能感兴趣的:(python,开发语言)