1. 什么是对象向上转型
将派生类对象赋值给基类对象、将派生类指针赋值给基类指针、将派生类引用赋值给基类引用,这在 C++ 中称为向上转型(Upcasting)。
理解基类和派生类之间的类型转换是理解C++语言面向对象编程的关键所在。(出自《c++ primer》)
2. 对象向上转型
对象之间不存在对象转型,转换过程中会忽略派生类的部分。因此,在这种转换的实际发生过程往往与我们期待的有所差别。
在对象指针或引用转换过程中,存在静态绑定和动态绑定,转换时非虚函数通常都是以静态绑定进行的,而虚函数是以动态绑定进行的。如下图:
因为,虚函数是以动态绑定的,因此,在向上转型后也是匹配的派生类的版本。而派生类的其他方法和属性都被隐藏了,可以通过专门的虚函数来间接访问或者调用。
3. 实例
#include <iostream>
using namespace std;
class A {
public:
A() : m(20) {}
void show() { cout << "A show: " << m << endl; }
virtual void display() { cout << "A display: " << m << endl; }
private:
int m;
};
class B : public A
{
public:
B() : m(40) {}
void show() { cout << "B show: " << m << endl; }
virtual void display() { cout << "B display: " << m << endl; }
private:
int m;
};
int main()
{
// 定义上执行对象
A* a = new B;
// 调用静态绑定的方法show
a->show();
// 调用动态绑定的方法display
a->display();
return 0;
}
虽然show方法基类和派生类都定义了,但因为是静态绑定,因此调用的是class A的show方法; 而display方法是动态绑定,因此在转型过程中绑定的是派生类的方法。运行结果如下:
A show: 20
B display: 40
4. 运用
学生管理系统中,我们拥有3个用户:管理员、教师和学生。他们都拥有一个用户id和其他一些共有的属性特性外,学生还拥有学号、班级等信息属性;教师拥有职工号和工资等信息属性;管理员也拥有一些特有属性。
通过问题分析得到一个大致设计思路,我们可以通过定义一个User类来管理3种类型用户的共有属性和方法,在通过继承User类进一步实现管理学生的Student类,管理教师信息的Teacher类, 管理管理员信息的Admin类。如果Student类、Teacher类和Admin类都具有一个方法show(),用以实现显示不同类型用户的信息,那么当不同类型用户登陆后如何显示显示其登陆用户的信息?
这问题有很多解决方法,比如下面这代码就是一种方法:
#include <iostream>
using namespace std;
class User {
public:
User() {}
/** 省略部分 **/
private:
/** 省略部分 **/
};
class Student : public User
{
public:
Student() {}
void show() { cout << "登陆用户是学生" << endl; }
/** 省略部分 **/
private:
/** 省略部分 **/
};
class Teacher : public User
{
public:
Teacher() {}
void show() { cout << "登陆用户是教师" << endl; }
/** 省略部分 **/
private:
/** 省略部分 **/
};
class Admin : public User
{
public:
Admin() {}
void show() { cout << "登陆用户是管理员" << endl; }
/** 省略部分 **/
private:
/** 省略部分 **/
};
int main()
{
// 定义3中类型用户
Student* student = nullptr;
Teacher* teacher = nullptr;
Admin* admin = nullptr;
int userType; // 用户类型
cout << "选择用户类型(1. 管理员 2. 教师 3. 学生),清选择: ";
cin >> userType;
/** 省略部分登陆操作 **/
if(userType == 1)
admin = new Admin;
else if(userType == 2)
teacher = new Teacher;
else if(userType == 3)
student = new Student;
/** 显示信息 **/
if(userType == 1)
admin->show();
else if(userType == 2)
teacher->show();
else if(userType == 3)
student->show();
/** 省略部分注销操作 **/
if(userType == 1)
delete admin;
else if(userType == 2)
delete teacher;
else if(userType == 3)
delete student;
return 0;
}
可以看出非常的累赘,对象向上转型就可以用来简化代码了,如下代码:
#include <iostream>
using namespace std;
class User {
public:
User() {}
virtual void show() = 0;
/** 省略部分 **/
private:
/** 省略部分 **/
};
class Student : public User
{
public:
Student() {}
void show() { cout << "登陆用户是学生" << endl; }
/** 省略部分 **/
private:
/** 省略部分 **/
};
class Teacher : public User
{
public:
Teacher() {}
void show() { cout << "登陆用户是教师" << endl; }
/** 省略部分 **/
private:
/** 省略部分 **/
};
class Admin : public User
{
public:
Admin() {}
void show() { cout << "登陆用户是管理员" << endl; }
/** 省略部分 **/
private:
/** 省略部分 **/
};
int main()
{
User* user = nullptr;
int userType; // 用户类型
cout << "选择用户类型(1. 管理员 2. 教师 3. 学生),清选择: ";
cin >> userType;
/** 省略部分登陆操作 **/
if(userType == 1)
user = new Admin;
else if(userType == 2)
user = new Teacher;
else if(userType == 3)
user = new Student;
user->show();
delete user;
return 0;
}
可以看出对象向上转型可以在某些环境中是非常好用的特性。