在面向对象中有一个原则就是赋值兼容性原则,就是一个子类对象完完全全可以当作一个父类对象来使用,可能会出现下面的情况,静态类型指的是变量自身的类型,动态类型指的是指针所指向对象的实际类型
-基类指针指向子类对象
-基类引用成为子类对象的别名
Base* p = new Derived();
Base& r = *p;
Base为静态类型 Derived为动态类型
如以下代码是个非常危险的行为,因为无法确定基类指针指向哪一个动态类型,换句话说就是基类指针是否可以强制类型转换为子类指针取决于动态类型
void test(Base* b)
{
Derived* d = static_cast<Derived*>(b);
}
为了可以得到动态类型,我们可以利用多态来帮我们解决
解决方案
1.在基类中定义虚函数返回具体的类型信息
2.所有派生类都必须实现类型相关的虚函数
3.每个类中的类型虚函数都需要不同的实现
例子:
#include <iostream>
#include <string>
using namespace std;
class Base
{
public:
virtual string type()
{
return "Base";
}
};
class Derived : public Base
{
public:
virtual string type()
{
return "Derived";
}
};
class Child : public Base
{
public:
virtual string type()
{
return "Child";
}
};
void test(Base* b)
{
Derived* d = static_cast<Derived*>(b);
}
int main(int argc,char *argv[])
{
Base b;
Derived d;
Child c;
test(&b);
test(&d);
test(&c);
return 0;
}
以上代码显然只有test(&d)合法,但是编译器却没有报错,但是实际上是一个潜在的危险,以下代码对此做出了修改
#include <iostream>
#include <string>
using namespace std;
class Base
{
public:
virtual string type()
{
return "Base";
}
};
class Derived : public Base
{
public:
virtual string type()
{
return "Derived";
}
void printf()
{
cout<<"i am derived"<<endl;
}
};
class Child : public Base
{
public:
virtual string type()
{
return "Child";
}
};
void test(Base* b)
{
//Derived* d = static_cast<Derived*>(b);
if(b->type() == "Derived")
{
Derived* d = static_cast<Derived*>(b);
d->printf();
}
}
int main(int argc,char *argv[])
{
Base b;
Derived d;
Child c;
test(&b);
test(&d);
test(&c);
return 0;
}
结果:
sice@sice:~$ ./a.out
i am derived
可以看出,这样的代码就可以在一定程度上避免类型转化的错误,但是在维护性上是有一个很大的问题,必须从基类开始提供类型虚函数,每一个派生类都需要去定义这个虚函数,且每个派生类的类型名必须唯一,非常麻烦!,所以这里引入新的关键字typeid用于获取类型信息
typeid关键字返回对应参数的类型信息
typeid返回一个type_info类对象
当typeid的参数为NULL时将抛出异常
int i = 0;
const type_info& tiv = typeid(i);
const type_info& tii = typeid(int);
cout<<(tiv == tii)<<endl;
注意事项:
当参数为类型时:返回静态类型信息
当参数为变量时:
不存在虚函数表--返回静态类型信息
存在虚函数表--返回动态类型信息
例子:
sice@sice:~$ ./a.out
1
4Base
7Derived
sice@sice:~$ cat test.cpp
#include <iostream>
#include <string>
#include <typeinfo>
using namespace std;
class Base
{
public:
virtual ~Base()
{
}
};
class Derived : public Base
{
public:
void printf()
{
cout<<"i am derived"<<endl;
}
};
void test(Base* b)
{
const type_info& tif = typeid(*b);
cout<<tif.name()<<endl;
}
int main(int argc,char *argv[])
{
int i = 0;
const type_info& tiv = typeid(i);
const type_info& tii = typeid(int);
cout<<(tiv == tii)<<endl;
Base b;
Derived d;
test(&b);
test(&d);//如果Base类中没有虚函数,则打印出4Base,至于打印出什么取决于编译器的不同
return 0;
}
结果:
sice@sice:~$ ./a.out
1
4Base
7Derived