dynamic_cast 用于继承体系中基类指针 (引用) 和派生类指针 (引用) 之间的强制转换
没有虚函数
class base {
public:
void test() {
cout << "base_test()" << endl;
}
protected:
int a=1;
};
class derived:public base {
public:
void test2()
{
cout << "derived_test()" << endl;
}
int c = 3;
protected:
int b=2;
};
派生类向基类可以无条件转换
int main()
{
base* bp = new base();
derived* dp = new derived();
//将 派生类 指针 转换成 基类指针, 两种方式都可以,也不需要多态
base* bs1 = dynamic_cast<base*>(dp);
base* bs2 = dp;
return 0;
}
int main()
{
base* bp = new base();
derived* dp = new derived();
//将 派生类 指针 转换成 基类指针, 两种方式都可以
base* bs1 = dynamic_cast<base*>(dp);
base* bs2 = dp;
//尝试将 bs1 转换回 派生类指针
//derived* dd1 = bs1; //报错: 无法从“base * ”转换为“derived* ”
// base 没有包含虚函数, 不是多态类型, 无法使用 dynamic_cast
//derived* dd2 = dynamic_cast(bs1); //运行时 dynamic_cast 的操作数必须包含多态类类型
// 直接 static_cast 可行
derived* dd3 = static_cast<derived*>(bs1);
dd3->test2(); // 输出derived_test()
cout << dd3->c << endl; //输出 3
return 0;
}
dynamic_cast 必须是在多态 (基类含有虚函数) 下才可行
static_cast 在非多态下可行
假设我们对 bp 指针直接转换, 同样 只有 static_cast 才可行
int main()
{
base* bp = new base();
derived* dp = new derived();
//derived* dd4 = bp; // 报错
// dynamic_cast 必须多态
//derived* dd5 = dynamic_cast(bp); // 报错 运行时 dynamic_cast 的操作数必须包含多态类类型
derived* dd6 = static_cast<derived*>(bp);
dd6->test2(); //输出 derived_test()
cout<<dd6->c<<endl; //输出 -33686019, 值未定义
return 0;
}
这个地方也不是特别能理解为什么 static_cast 可以成功???
现在给 基类 base 增加一个虚函数
class base {
public:
//增加 虚函数
virtual void func1() {
cout << "base_func1()" << endl;
}
void test() {
cout << "base_test()" << endl;
}
protected:
int a=1;
};
class derived:public base {
public:
void test2()
{
cout << "derived_test()" << endl;
}
int c = 3;
protected:
int b=2;
};
int main()
{
base* bp = new base();
derived* dp = new derived();
//将 派生类 指针 转换成 基类指针, 两种方式都可以
base* bs1 = dynamic_cast<base*>(dp);
base* bs2 = dp;
//尝试将 bs1 转换回 派生类指针
//derived* dd1 = bs1; //报错: 无法从“base * ”转换为“derived* ”
// base 包含虚函数, 多态类型, 可以正确使用 dynamic_cast
derived* dd2 = dynamic_cast<derived*>(bs1); //运行时 dynamic_cast 的操作数必须包含多态类类型
if (dd2)
{
dd2->test2(); // 输出 derived_test()
cout << dd2->c << endl; // 输出 3
}
// 直接 static_cast 依然可行
derived* dd3 = static_cast<derived*>(bs1);
if (dd3)
{
dd3->test2(); // 输出 derived_test()
cout << dd3->c << endl; // 输出 3
}
return 0;
}
多态情况下,dynamic_cast 可以运行通过了
static_cast 一直可以通过,是不是多态都可以
仍然尝试将 基类指针bp 转换成 派生类指针
int main()
{
base* bp = new base();
derived* dp = new derived();
derived* dd5 = dynamic_cast<derived*>(bp);
if (dd5)
{
dd5->test2();
cout<<dd5->c << endl;
}
else // dd5 为空 输出 "空指针"
{
cout << "空指针" << endl;
}
derived* dd6 = static_cast<derived*>(bp);
if (dd6) // dd6 非空
{
dd6->test2(); // 输出 derived_test()
cout << dd6->c << endl; // 输出 -33686019
}
else
{
cout << "空指针" << endl;
}
return 0;
}
可能是这样:dynamic_cast 专门用于继承中的基类、派生类转换,而且得是多态 (虚函数) 场景下
第 1 次转换毫无疑问,第 2 次转换 dynamic_cast 检查 该基类指针 的动态类型 是 派生类,则 dynamic_cast 成功转换,因为该基类指针确实指向了一个派生类对象,转换是安全的。当然用 static_cast 转换也可行。
这种情况下,基类指针实际上指向的是基类对象,
虽然 static_cast= 可以强制实现这种转换,但是不合我们的理解,不过转换后确实可以访问派生类的函数,以及其它成员(这应该要从内存角度考虑了,有机会再探索)
相反,dynamic_cast 发现这个指针并没有指向派生类对象,所以没有进行转换,而是返回了nullptr,所以确实是 dynamic_cast 的处理更合理一点 (根本就没有指向派生类,那就不要转换了),避免后续可能出错。
派生类指针 向 基类指针 转换,无条件可行
基类指针指向派生类对象情况下,要实现基类指针 转换到 派生类指针
基类指针指向基类对象情况下,要实现基类指针 转换到 派生类指针
note: 凡是基类指针到派生类指针的转换,dynamic_cast 都需要多态
引用和指针的情况类似,dynamic_cast 中,指针转换失败返回nullptr,但是引用无法是空引用,所以引用转换失败时返回 std::bad_cast 异常(这里都是指 基类 向 派生类 转换)
typeid 和 dynamic_cast 实现 运行时类型识别 (run-time type identification ,RTTI)功能的 2 个重要运算符
typeid 用于得到对象的类型,是否多态会影响到 typeid 的结果
同样使用刚才的 测试 类型 base 和 derived
class base {
public:
void test() {
cout << "base_test()" << endl;
}
protected:
int a=1;
};
class derived:public base {
public:
void test2()
{
cout << "derived_test()" << endl;
}
int c = 3;
protected:
int b=2;
};
非多态下,typeid 的结果和 静态类型保持一致
int main()
{
//基类对象指针
base* bp = new base();
cout << typeid(*bp).name() << endl; //输出 class base
//派生类对象指针
derived* dp = new derived();
cout << typeid(*dp).name() << endl; //输出 class derived
//将 派生类 指针 转换成 基类指针, 两种方式都可以
base* bs1 = dp;
base* bs2 = dynamic_cast<base*>(dp);
cout << typeid(*bs1).name() << endl; //非多态下输出 class base
cout << typeid(*bs2).name() << endl; //非多态下输出 class base
return 0;
}
note: typeid() 返回的结果是一种 type_info 的对象,还要调用 name() 函数获得具体的类型名称
可以看到,尽管 基类指针 bs1 和 bs2 都指向了派生类对象,但是结果依然是 静态类型,也就是定义 时 使用的类型
class base {
public:
//增加 虚函数
virtual void func1() {
cout << "base_func1()" << endl;
}
void test() {
cout << "base_test()" << endl;
}
protected:
int a=1;
};
class derived:public base {
public:
void test2()
{
cout << "derived_test()" << endl;
}
int c = 3;
protected:
int b=2;
};
再次运行刚刚的测试代码
int main()
{
//基类对象指针
base* bp = new base();
cout << typeid(*bp).name() << endl; //输出 class base
//派生类对象指针
derived* dp = new derived();
cout << typeid(*dp).name() << endl; //输出 class derived
//将 派生类 指针 转换成 基类指针, 两种方式都可以
base* bs1 = dp;
base* bs2 = dynamic_cast<base*>(dp);
cout << typeid(*bs1).name() << endl; //输出 class derived
cout << typeid(*bs2).name() << endl; //输出 class derived
return 0;
}
此时 bs1 和 bs2 的 typeid 的结果都是 派生类 类型,
按照书里的说法,多态场景下,* bs1 和 * bs2 会在运行时求值,由于它们指向派生类,所以得到派生类的结果
dynamic_cast
#include
using namespace std;
class base {
public:
//增加 虚函数
virtual void func1() {
cout << "base_func1()" << endl;
}
void test() {
cout << "base_test()" << endl;
}
protected:
int a=1;
};
class derived:public base {
public:
void test2()
{
cout << "derived_test()" << endl;
}
int c = 3;
protected:
int b=2;
};
int main()
{
base* bp = new base();
derived* dp = new derived();
//将 派生类 指针 转换成 基类指针, 两种方式都可以
base* bs1 = dynamic_cast<base*>(dp);
base* bs2 = dp;
//尝试将 bs1 转换回 派生类指针
//derived* dd1 = bs1; //报错: 无法从“base * ”转换为“derived* ”
// base 包含虚函数, 多态类型, 可以正确使用 dynamic_cast
//derived* dd2 = dynamic_cast(bs1); //运行时 dynamic_cast 的操作数必须包含多态类类型
//if (dd2)
//{
// dd2->test2();
// cout << dd2->c << endl;
//}
// 直接 static_cast 可行
//derived* dd3 = static_cast(bs1);
//if (dd3)
//{
// dd3->test2();
// cout << dd3->c << endl;
//}
//derived* dd4 = bp; // 报错
// dynamic_cast 必须多态
//derived* dd5 = dynamic_cast(bp); //运行时 dynamic_cast 的操作数必须包含多态类类型
//if (dd5)
//{
// dd5->test2();
// cout<c << endl;
//}
//else
//{
// cout << "空指针" << endl;
//}
//derived* dd6 = static_cast(bp);
//if (dd6)
//{
// dd6->test2();
// cout << dd6->c << endl;
//}
//else
//{
// cout << "空指针" << endl;
//}
return 0;
}
typeid
#include
using namespace std;
class base {
public:
//增加 虚函数
virtual void func1() {
cout << "base_func1()" << endl;
}
void test() {
cout << "base_test()" << endl;
}
protected:
int a=1;
};
class derived:public base {
public:
void test2()
{
cout << "derived_test()" << endl;
}
int c = 3;
protected:
int b=2;
};
int main()
{
//基类对象指针
base* bp = new base();
cout << typeid(*bp).name() << endl; //输出 class base
//派生类对象指针
derived* dp = new derived();
cout << typeid(*dp).name() << endl; //输出 class derived
//将 派生类 指针 转换成 基类指针, 两种方式都可以
base* bs1 = dp;
base* bs2 = dynamic_cast<base*>(dp);
//非多态下输出 class base
//多态下输出 class derived
cout << typeid(*bs1).name() << endl;
//非多态下输出 class base
//多态下输出 class derived
cout << typeid(*bs2).name() << endl;
return 0;
}