相信通过之前的学习,你也已经对类有了深刻的了解,那么请利用你所学的知识,想一想下面这道题。
/* 函数名: foo
* 函数声明:
* template <class B, class D>
* bool foo();
* 函数注解:
* B代表判断基类
* D代表判断子类
* foo返回一个布尔值
* 如果D是B的子类,返回true
* 如果D不是B的子类,返回false
*/
很新奇的题目吧,你可能一下子被蒙住了。这道题牵涉到函数重载(overload
),下面就是本题答案。
/* 函数名: foo
* 函数声明:
* template <class B, class D>
* bool foo();
* 函数注解:
* B代表判断基类
* D代表判断子类
* foo返回一个布尔值
* 如果D是B的子类,返回true
* 如果D不是B的子类,返回false
*/
template <class B, class D>
class Inherit
{
public:
bool result();
protected:
bool foo(B *var);
bool foo(void *var);
};
bool Inherit::result()
{
D *d = 0;
return foo(0);
}
bool Inherit::foo(B *var)
{return true;}
bool Inherit::foo(void *var)
{return false;}
template <class B, class D>
bool foo()
{return Inherit<B,D>().result();}
思路就是,通过函数重载,对于B
的子类,将调用bool foo(B *var)
,对于其他类型,将调用bool foo(void *var)
这是因为从子类指针到父类指针比从指针到void *
的距离短
当然我一开始也并不觉得是这样,因为这怎么又可比性呢?我认为会报错的。
但我亲自尝试了一下,发现确实可行。
再来一道和多态有关的。
/* 函数名: foo
* 函数声明:
* template <class B, class D>
* bool inherits(B *var);
* 函数注解:
* B代表判断子类
* D代表判断基类
* D一般是B的子类(不一定是)
* var的类型可以是B,也可以是B的子类(多态)
* 如果var的类型是D的子类,foo返回true
* 如果var的类型不是D的子类,foo返回false
*/
这道题有点绕,举个例子
class A {};
class B: public A {};
class C {};
int main()
{
A *a = new B;
foo<B>(a); // 返回true,因为a的类型是B,B是B的子类
foo<C>(a); // 返回false,因为a的类型是B,B不是C的子类
B *b = new B;
foo<A>(b); // 返回true,因为b的类型是B,B是A的子类
delete a.b;
}
就需要满足上述的效果。
这道题要用到动态类型转换(dynamic cast
),你可能不知道
template <class B, class D>
bool foo(B *var)
{
D *d = dynamic_cast<D *>(var);
return !!d;
}
代码很短,主要是第3行的dynamic_cast
,这个运算符可以帮助我们判断var
是不是D
的子类
dynamic_cast
允许把一个原本为子类的父类变量转为原本类型的父类。
听起来有点绕口,其实很简单。
假如A->B->C
,即C
是B
的子类,B
是A
的子类
现有变量C *var
,利用多态特性转换为A *var
,那么我们就不能直接看出var
是否继承B
,这时dynamic_cast
可以试图将var
转换为B *
类型,如果成功,返回转换后的值,如果失败,返回空指针。
这就正好满足了我们的需求。
但dynamic_cast
运行较慢,好像是通过源代码查找的方式确定的。
所以能用第一种就用第一种。
本序列的文章:
C++类的使用(一)
C++类的使用(二)—— explicit构造与const成员变量赋值
C++类的使用(三)—— 封装
C++类的使用(四)—— 继承
C++类的使用(五)—— 多态
C++类的使用(六)—— 判断继承