基类和派生类互转

一.基类和派生类的裸指针转换

  • 派生类的地址或者指针赋值给基类指针时,一般都用隐式转换。(也可以使用static_cast、dynamic_cast显示转换)

反过来,

  • 基类指针赋值给派生类指针的时候,必须要显示转换:使用dynamic_cast或者static_cast。

  • 例子如下

#include <iostream>

class base
{
public:
	virtual ~base(void) = default;

};

class derived :public base
{

};

int main()
{

	// 派生类对象
	derived derivedobj;
	std::cout << "派生类对象的地址是:" << &derivedobj << std::endl;

	//===========================派生类的地址或者指针赋值给基类指针===========================//
	// 基类裸指针保存派生类对象的地址(隐式转换)
	base *pointer1 = &derivedobj;
	std::cout << "隐式转换后,基类裸指针保存的地址是:" << pointer1 << std::endl;

	// 基类裸指针保存派生类对象的地址(static_cast转换)
	base *pointer2 = static_cast<base *>(&derivedobj);
	std::cout << "static_cast转换后,基类裸指针保存的地址是:" << pointer2 << std::endl;

	//============================基类指针赋值给派生类指======================================//
	// 用派生类裸指针保存基类裸指针的值(不能隐式转换)
    //derived *pointer3 = pointer1; // 去掉注释将会编译报错

	// 用派生类裸指针保存基类裸指针的值(dynamic_cast转换)
	derived *pointer4 = dynamic_cast<derived *>(pointer1);
	std::cout << "dynamic_cast转换后,派生类裸指针保存的地址是:" << pointer4 << std::endl;

	// 用派生类裸指针保存基类裸指针的值(static_cast转换)
	derived *pointer5 = static_cast<derived *>(pointer1);
	std::cout << "static_cast转换后,派生类裸指针保存的地址是:" << pointer5 << std::endl;

	return 0;
}
  • 从输出结果可以看出,都是同一个内存地址

派生类对象的地址是:003AFA0C
隐式转换后,基类裸指针保存的地址是:003AFA0C
static_cast转换后,基类裸指针保存的地址是:003AFA0C
dynamic_cast转换后,派生类裸指针保存的地址是:003AFA0C
static_cast转换后,派生类裸指针保存的地址是:003AFA0C

二.dynamic_cast和static_cast的区别

1、对于有继承关系的两个类:

  • (1)子类转成父类dynamic_cast和static_cast都没有问题.
  • (2)父类转成子类,dynamic_cast要求父类中有虚函数,否则编译不通过。static_cast不作此要求,编译通过。
    在有虚函数的前提下,如果父类指针的确实指向的是子类实例,dynamic_cast转换成功,否则返回NULL;
    static_cast对于转换前的指针是否指向实际子类实例,不作要求,都能转换成功。
  • (3)在编译通过成功,且返回指针不为空的前提下,两者转换结果指针,都可以用来读写父类和子类成员函数和变量。
  • (4)如果父类指针不是指向子类实例,编译都能通过,但是dynamic_cast返回为NULL,不能操作对象;
    static_cast返回非空指针,可以读写父类成员变量,也能调用其成员函数。子类的成员函数可以调用,但是当操作涉及子类成员变量时候,不成功。

2、对于没有继承关系的两个类

static_cast可以编译通过,dynamic_cast不能编译通过。两者都不能读写成员变量和函数。

3、demo(即二.1.(4))

#include <iostream>

class base
{
public:
	virtual ~base(void) = default;

};

class derived :public base
{
public:
		int a=0;
};

class test : public base
{
};

int main()
{

	std::cout << std::boolalpha;

	// 两个不同的派生类对象
	derived derivedobj;
	test testobj;

	// 基类裸指针保存派生类对象的地址
	base *pointer = &derivedobj;

	test *pointer2 = dynamic_cast<test *>(pointer);
	std::cout << "test指针保存derivedobj的地址(dynamic_cast):" << std::endl;
	std::cout << "是否成功:" << (pointer2 != nullptr) << std::endl << std::endl;
	
	test *pointer4 = static_cast<test *>(pointer);
	std::cout << "test指针保存derivedobj的地址(static_cast):" << std::endl;
	std::cout << "是否成功:" << (pointer4 != nullptr) << std::endl << std::endl;

	return 0;
}

输出结果

test指针保存derivedobj的地址(dynamic_cast):
是否成功:false

链接: dynamic_cast和static_cast的异同.

其他

  • 由于dynamic_cast是在运行的时候进行检测和转换的,所以会影响到运行时的性能。

  • 不过,在良好的程序设计中,不会也不应该频繁地将基类指针(或引用)转换成派生类指针(或引用),也就是说,不应该频繁地使用dynamic_cast。如果你的代码频繁地使用了dynamic_cast,应该要考虑,继承是否设计好。

  • 因此,在良好的程序设计中,合理使用dynamic_cast是没有问题的。

三.dynamic_cast 转换引用

  • dynamic_cast转换指针时,转换失败可以通过nullptr来表达。
  • 而引用就不能。所以dynamic_cast转换引用使用的是抛出异常std::bad_cast。std::bad_cast在标准库typeinfo中。
#include <iostream> // std::cout std::endl
#include <typeinfo> // std::bad_cast

class base
{
public:
    virtual ~base(void) = default;
};

class derived : public base
{
};

class test : public base
{
};

int main(void)
try
{
    std::cout << std::boolalpha;

    // 两个不同的派生类对象
    derived derivedobj;
    test testobj;

    // 基类引用保存派生类对象
    base &object = derivedobj;

    derived &ref1 = dynamic_cast<derived &>(object);
    std::cout << "成功转换成derived引用" << std::endl;

    test &ref2 = dynamic_cast<test &>(object);
    std::cout << "成功转换成test引用" << std::endl;

    return 0;
}
catch (const std::bad_cast &)
{
    std::cout << "转换失败" << std::endl;
}

四.基类和派生类的智能指针转换

  • 基类和派生类的智能指针转换要使用std::dynamic_pointer_cast和std::static_pointer_cast。
  • (std::dynamic_pointer_cast和dynamic_cast原理一样,std::static_pointer_cast和static_cast原理一样。)

参考
1.基类和派生类相互转换.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郑同学的笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值