<5> 面向对象到底有什么(中)?

在<3> 面向对象到底有社么(上)一文中,我们说了下关于面向对象和面向过程的区别和优劣性。在面向对象里边,也谈了下关于“面向对象三大特性”的其中一个特性“封装性”的简单理解。在这一文中,我们主要一起来了解下关于面向对象的第二个特性“继承”的理解,一起来看下“继承”到底是什么?继承到底有什么作用?以及“继承”在什么情况下会用到?继承的优点在哪里?

2.2 ”继承“到底是什么?为什么要有它这个东西?

我是觉得,现在的名称翻译还是挺符合“顾名思义”的原则的,继承在我们一般人的眼里,就代表了“依法拿到遗产”、“把前人的文化、知识传承过来”等意思,在高级程序设计语言这里,其实也有类似的意味。

还是接着我们上一篇文章的“Person”类作为例子,接着说。实际上,在我们的项目中,“人”只是一个比较宽泛的“类别”,在这个社会群体中,“学生”,“老师”,“校长”等等社会职业属于“人”这个类型,但是这些社会职业本身也都是单独的“类别”。假设:我们在“Person”类里边添加关于“学生”,“老师”,“校长”的一些信息,结果会是这样的:

//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
// 类的封装
class Person{

public:
	Person(int age, char gender, std::string name)
		:_age(age),
		 _gender(gender),
		 _name(name) 
	{
		_score = new double[10];
	}

	~Person();

public:
	int  _age;
	char _gender;
	std::string _name;

	// 学生
	double *_score;
	std::string _studentID;
	std::string _major;

	// 老师
	std::vector<std::string> _lesson;
	std::string _teacherID;

	// 校长
	std::string _school;
	//···
	//···
	//···

public:
	const int get_age() { return _age; }
	const char get_gender() { return _gender; }
	const std::string get_name() { return _name; }
	void set_age(const int &value);
	void set_gender(const char &value);
	void set_name(const std::string &value);
};


void Person::set_age(const int &value){
	this->_age = value;
}

void Person::set_gender(const char &value) {
	this->_gender = value;
}

void Person::set_name(const std::string &value) {
	this->_name = value;
}

Person::~Person()
{
	//
}



int main() {

	// 声明一个Person类型的对象
	// 请注意:对象的概念在这里开始出现,因为Person是一个集合,一个类型,那么类型的一个一个实际的例子,就是对象
	Person m_person(25, '男', "chengzhen");

	// 获得年龄
	m_person.get_age();

	// 获得性别
	m_person.get_gender();

	// 获得姓名
	m_person.get_name();

	// 设置年龄
	m_person.set_age(30);

	// 设置性别
	m_person.set_gender('nv');

	// 设置姓名
	m_person.set_name("Charmain");

	std::cin.get();
}

如果我们在某个地方只用学生这个“类别”,我们就不得不来一次“Person student(25,'男',“who”)“一次,但是我们发现,在创建一个对象并初始化的时候,类已经为我们创建好了”老师“,”校长“等社会角色身上存在的一些特性(老师教授的”课“有哪些,校长管理的是”哪个学校“等等)。而我们明白的是,学生并不需要知道具备这些特性,因为他们只需要做好自己,了解自己的特性就好。由于我们把这些内容都融合在一个类里边,所以每次在创建对象的时候,就会有多余的数据被创建,比如:std::vector<std::string> _lesson、std::string _school等等,造成代码冗余,工程文件过大,不易管理、可读性不高。当然,我们也可以这么来写设计类:

//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
// 类的封装
class Person{

public:
	Person(int age, char gender, std::string name)
		:_age(age),
		 _gender(gender),
		 _name(name) 
	{}

	~Person();

public:
	int  _age;
	char _gender;
	std::string _name;

public:
	const int get_age() { return _age; }
	const char get_gender() { return _gender; }
	const std::string get_name() { return _name; }
	void set_age(const int &value);
	void set_gender(const char &value);
	void set_name(const std::string &value);
};

//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
// 类的封装
class Student {

public:
	Student(int age, char gender, std::string name)
		:_age(age),
		_gender(gender),
		_name(name)
	{
		_score = new double[10];
	}

	~Student();

public:
	int  _age;
	char _gender;
	std::string _name;

	// 学生
	double *_score;
	std::string _studentID;
	std::string _major;

public:
	const int get_age() { return _age; }
	const char get_gender() { return _gender; }
	const std::string get_name() { return _name; }
	void set_age(const int &value);
	void set_gender(const char &value);
	void set_name(const std::string &value);
};

//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
// 类的封装
class Teacher {

public:
	Teacher(int age, char gender, std::string name)
		:_age(age),
		_gender(gender),
		_name(name)
	{}

	~Teacher();

public:
	int  _age;
	char _gender;
	std::string _name;

	// 老师
	std::vector<std::string> _lesson;
	std::string _teacherID;

public:
	const int get_age() { return _age; }
	const char get_gender() { return _gender; }
	const std::string get_name() { return _name; }
	void set_age(const int &value);
	void set_gender(const char &value);
	void set_name(const std::string &value);
};

//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
// 类的封装
class Principal {

public:
	Principal(int age, char gender, std::string name)
		:_age(age),
		_gender(gender),
		_name(name)
	{}

	~Principal();

public:
	int  _age;
	char _gender;
	std::string _name;

	// 校长
	std::string _school;
	//···
	//···
	//···

public:
	const int get_age() { return _age; }
	const char get_gender() { return _gender; }
	const std::string get_name() { return _name; }
	void set_age(const int &value);
	void set_gender(const char &value);
	void set_name(const std::string &value);
};

看见上边的内容,可以发现每个一共有四个类,每个类中都有相同的内容:年龄、性别、姓名、获取年龄、获取性别、获取姓名,如果以后需要添加内容,也许会有数十个甚至上百个成员函数或者成员变量是相同的。会导致代码的复用性不高,过于冗余,不够精简。因此,这个时候,我们可以用上我们的面向对象的第二个特性”继承“了。

2.3 ”继承“该怎么用?

我们依然是以”Person“类为原型来设计”学生“、”老师“、”校长“等社会角色。在这里使用了”继承“的相关内容:

#include <iostream>
#include <vector>
#include <cmath>
#include <string>




//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
// Person ( 基类 )


class Person {

public:
	Person(int age, char gender, std::string name)
		:_age(age),
		 _gender(gender),
		 _name(name)
	{}

	~Person();

public:
	int  _age;
	char _gender;
	std::string _name;

public:
	const int get_age() { return _age; }
	const char get_gender() { return _gender; }
	const std::string get_name() { return _name; }
	void set_age(const int &value);
	void set_gender(const char &value);
	void set_name(const std::string &value);
};


void Person::set_age(const int &value) {
	this->_age = value;
}

void Person::set_gender(const char &value) {
	this->_gender = value;
}

void Person::set_name(const std::string &value) {
	this->_name = value;
}

Person::~Person()
{
	//
}



//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
// Student ( 派生类,继承自Person )

class Student :public Person {

public:
	Student(int age, char gender, std::string name,
			double *score,std::string ID,
			std::string major)
								:	Person(age,gender,name),
									_score(score),
									_studentID(ID),
									_major(major)
	{}

	~Student(){}

private:
	double *_score;
	std::string _studentID;
	std::string _major;

public:
	const double* get_score() { return _score; }
	const std::string get_id() { return _studentID; }
	const std::string get_major() { return _major; }
	void set_score(const double* score) { std::memcpy(_score, score, sizeof(score) / sizeof(score[0])); }
	void set_id(const std::string& id) { _studentID = id; }
	void set_major(const std::string& major) { _major = major; }
};



//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
// Teacher ( 派生类,继承自Person )

class Teacher :public Person {

public:
	Teacher(int age, char gender, std::string name,
			std::vector<std::string> lesson,
		    std::string id)
							:	Person(age, gender, name),
								_lesson(lesson),
								_teacherID(id)
	{}

	~Teacher() {}

private:
	std::vector<std::string> _lesson;
	std::string _teacherID;

public:
	const std::vector<std::string> get_lesson() { return _lesson; }
	const std::string get_id() { return _teacherID; }
	void set_lesson(const std::vector<std::string> lesson) { _lesson.assign(lesson.begin(), lesson.end()); }
	void set_id(const std::string& id) { _teacherID = id; }
};



//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
// Principal ( 派生类,继承自Person )

class Principal :public Person {

public:
	Principal(int age, char gender, std::string name,
		std::string school)
		: Person(age, gender, name),
		_school(school)
	{}

	~Principal() {}

private:
	std::string _school;

public:
	const std::string get_school() { return _school; }
	void set_school(const std::string& school) { _school = school; }
};



int main() {

	// 声明一个Person类型的对象
	// 请注意:对象的概念在这里开始出现,因为Person是一个集合,一个类型,那么类型的一个一个实际的例子,就是对象
	Person m_person(25, '男', "chengzhen");

	// 获得年龄
	m_person.get_age();

	// 获得性别
	m_person.get_gender();

	// 获得姓名
	m_person.get_name();

	// 设置年龄
	m_person.set_age(30);

	// 设置性别
	m_person.set_gender('nv');

	// 设置姓名
	m_person.set_name("Charmain");

	std::cin.get();
}

这样看起来,不管是Student、Teacher、还是Principal类,都具备了Person的属性,同时也拥有了自己的特性,展现了三个不同人群之间的差异,但是同时,这种“is-a”的关系,也是继承的一个重要关系,即:派生类也是一个基类。并且在使用类的时候,按需使用。对于功能的扩展好,都比较明晰,减少了冗余代码,增加了可读性,这些也是“继承”能够被支持的重要原因之一。

未完,待续。








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值