IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 基类和派生类互转 -> 正文阅读

[C++知识库]基类和派生类互转

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

  • 派生类的地址或者指针赋值给基类指针时,一般都用隐式转换。(也可以使用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转换指针时,转换失败可以通过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.基类和派生类相互转换.

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-07 22:27:40  更:2022-04-07 22:29:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:31:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码