接着我们上次没有介绍完的内容,我们说OOP的三大特性,还有个特性是“多态”。乍一看,这个名字有点吓人。本篇博客将介绍“多态”是什么?为什么会用到“多态”这个特性?在哪里会用到?等这三个问题,来巩固自己对于面向对象的理解。
2.4 “多态”究竟是什么?(C++)
“多态”从字面意思上来看是“多种形态”的意思,在我们的面向对象中,多态意味着基类的形态是可以多变的,通过多态可以将基类对象赋予子类的特性,对于不同的子类,使得基类产生不同的解释,执行不同的操作,生成不同的结果。在C++中,实现多态有虚函数、抽象类等技术。
2.5 “为什么”会用到多态的特性?
我们依然用之前的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 describe();
};
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;
}
void Person::describe() {
std::cout << "I am Person" << std::endl;
}
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; }
void describe();
};
void Student::describe() {
std::cout << "I am student" << std::endl;
}
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
// 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; }
void describe();
};
void Teacher::describe() {
std::cout << "I am Teacher" << std::endl;
}
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
// 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; }
void describe();
};
void Principal::describe() {
std::cout << "I am Teacher" << std::endl;
}
int main() {
// 声明并初始化一个Person类
double score[2] = { 90,100 };
Person* P = new Student(13, '男', "chengzhen", score, "1402110", "软件工程");
P->describe();
std::cout << std::endl;
std::cin.get();
}
以上代码的输出结果是什么:
比较奇怪呀,我们直观上来看,主函数中new了一个Student类型的对象,并进行了初始化,但是在调用describe函数的时候,却调用了基类的describe函数,屏蔽了子类的describe函数,造成了一种使用上的迷惑。为了能够让可以不同的子类当做基类来看,屏蔽不同子类之间的差异,使得基类可以按照赋值给它的子类的特性去运作,从而写出通用的代码,来适应需求的不断变化,C++支持“多态”这个比较重要的特性。接下来,我们来看一下,“多态”究竟该怎么实现?
2.6 多态的实现有哪些方式?
1)虚函数
完了,感觉又多了一个名词,但是没关系,我们可以一点点的来拨开多态的迷雾。什么是虚函数,虚函数是指函数前加上“virtual”这个关键字的函数叫做“虚函数”。虚函数是为了实现多态而产生的。还是上边的例子,我们只需要简单的添加一些内容,就可以实现多态。看下边:
#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)
{}
virtual ~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);
virtual void describe();
};
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;
}
void Person::describe() {
std::cout << "I am Person" << std::endl;
}
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; }
virtual void describe();
};
void Student::describe() {
std::cout << "I am student" << std::endl;
}
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
// 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; }
virtual void describe();
};
void Teacher::describe() {
std::cout << "I am Teacher" << std::endl;
}
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
// 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; }
virtual void describe();
};
void Principal::describe() {
std::cout << "I am Teacher" << std::endl;
}
int main() {
// 声明并初始化一个Person类
double score[2] = { 90,100 };
Person* P = new Student(13, '男', "chengzhen", score, "1402110", "软件工程");
P->describe();
std::cout << std::endl;
std::cin.get();
}
输出结果是:
可以看见,输出的结果是我们预想到的。我们创建了一个Student对象,但是是在基类Person中派生的,因此基类拥有了Student类的特性,调用discrube函数,使得调用的是子类的函数,其他类也一样:Person* P = new Teacher(),Person* P = new Principal()等等。
2)抽象类
带有纯虚函数的类,就是C++的抽象类。工厂模式使用的就是这种方式。我会在设计模式中以“工程模式”为例子来实现这种方法实现的多态。
总之一句话,多态的支持,使得我们能够屏蔽类的不同特性,而专注于使用。