(P31)继承:转换与继承 ,派生类到基类的转换 ,基类到派生类的转换

2024-06-08 06:08

本文主要是介绍(P31)继承:转换与继承 ,派生类到基类的转换 ,基类到派生类的转换,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 1.转换与继承
    • 2.派生类到基类的转换
    • 3.基类到派生类的转换

1.转换与继承

  • 派生类对象也是基类对象。这意味着,在使用基类的地方可以用派生类来代替。
    eg:教师类继承至人类,那么教师也是人

2.派生类到基类的转换

  • 派生类和基类谁大?基类比派生类的适用集合更大,派生类是基类的具体化
  • 当派生类以public方式继承基类时,编译器可自动执行的转换(向上转型upcasting安全转换)
    (1)派生类对象指针自动转化为基类对象指针
    基类指针指向某某,这样去理解
    (2)派生类对象引用自动转化为基类对象引用
    (3)派生类对象自动转换为基类对象(派生类特有的成员消失)
  • 当派生类以private/protected方式继承基类时
    (1)派生类对象指针(引用)转化为基类对象指针(引用)需用强制类型转化。但是不能用static_cast,要用reinterpret_cast
    (2)不能把派生类对象强制转换为基类对象
  • eg:P31\01.cpp
#include <iostream>
#include <string>
using namespace std;class Employee
{
public:Employee(const string& name, const int age, const int deptno) : name_(name),age_(age), deptno_(deptno){}
private:string name_;int age_;int deptno_;//部门号
};//经理类继承至员工类
class Manager : public Employee
{
public:Manager(const string& name, const int age, const int deptno, int level): Employee(name, age, deptno), level_(level)
private:int level_;
};class Manager2 : private Employee
{
public:Manager(const string& name, const int age, const int deptno, int level): Employee(name, age, deptno), level_(level)
private:int level_;
};int main(void)
{Employee el("zhangsan", 25, 20);Manager ml("lisi", 38, 20, 10);Manager2 m2("wangwu", 40, 15, 8);Employee* pe;Manager* pm;Manager2* pm2;pe = &el;//基类指针指向基类对象pm = &ml;//派生类指针指向派生类对象pm2 = &m2;//基类指针指向派生类对象,换句话就是:派生类对象指针可以转化为基类指针。将派生类对象看成基类对象pe = &ml;pm = &el;//error,基类指针无法转化为派生类指针,无法将基类对象看成是派生类对象。//基类比派生类的适用集合更大,派生类是基类的具体化el = ml;//派生类对象可以转化为基类对象。因为可以将派生类对象看成是基类对象//对象转化,会产生对象切割object slicing//调用赋值运算符完成的//派生类指针转换为基类指针//私有或保护继承时,生类对象指针不可以转化为基类指针pe = pm2;//等价于pe = &pm2;因为&pm2的类型也是Manager*,都是errorpe = static_cast<Employee*>(pm2);//error,这里的转化编译器不认识这pe = (Employee*)(pm2);//C风格的强制转化是可以的pe = reinterpret_cast<Employee*>(pm2);//是可以的// e1 = m2;//私有或保护继承时,派生类对象不可以转化为基类对象,error,自动或强制转化也不行,如下:// e1 = reinterpret_cast<Manager2>(pm2);//error// e1 = (Manager2)pm2;//error//基类指针转化为派生类指针// pm = pe;//errorpm = static_cast<Manager*>(pe);//是可以的,但是不安全,pe指向的是基类对象,但是pm可以访问level_,该成员基类是没有的pm2 = static_cast<Manager2*>(pe);//是可以的//基类对象无法强制转化为派生类对象ml = el;//errorml = static_cast<Manager>(el);//errorml = reinterpret_cast<Manager>(el);//errorreturn 0;
}/*
回顾各种转化
静态转化:3种:
static_cast 用于编译器认可的静态转化,eg:从char到int,从double到int,或者具有转换构造函数,或者
重载了转换类型运算符
reinterpret_cast 重新解释,用于编译器不认可的静态转换。eg:从int *转为int,在转型的过程中,不做任何对齐操作
const_cast 去除常量性动态转化:1钟:
dynamic_cast 用于动态转换,安全的向下转型。用于多态
*/

小结

  • 对于public或者private继承的向上或者向下的指针强转而言,都是可以成功的,但是向下强转可能不安全
  • 对于public或者private继承的向上或者向下的类对象转换而言,向下转型都不可以(除非使用转换构造或者重载类型转换运算符),向上转型只有public可以,但是可能不安全

3.基类到派生类的转换

  • 基类对象指针(引用)可用强制类型转换为派生类对象指针(引用),而基类对象无法执行这类转换

  • 向下转型不安全,且没有自动转换的机制

  • 其他说明:
    基类对象转换为派生类对象是可以转换的,但是往往不去这样实现
    这样实现,会带来很多的语义错误
    语法上是可以转换的
    方法有2个:
    (1)转换构造函数:将其他类型转换为类类型,P31\02.cpp
    (2)类型转换运算符重载:将类类型转换为其他类型,P31\03.cpp

  • eg:P31\02.cpp

#include <iostream>
#include <string>
using namespace std;class Employee
{
public:Employee(const string& name, const int age, const int deptno) : name_(name),age_(age), deptno_(deptno){}
private:string name_;int age_;int deptno_;//部门号
};//经理类继承至员工类
class Manager : public Employee
{
public:Manager(const string& name, const int age, const int deptno, int level): Employee(name, age, deptno, level), level_(level)//从语法上来演示基类对象可以转化为派生类对象,但是没有意义//带一个参数的构造函数,称之为转换构造函数Manager(const Employee& other) : Employee(other), level_(-1) {}
private:int level_;
};//基类对象转换为派生类对象是可以转换的,但是往往不去这样实现
//这样实现,会带来很多的语义错误
//语法上是可以转换的int main(void)
{Employee el("zhangsan", 25, 20);Manager ml("lisi", 38, 20, 10);//方法(1):转换构造函数:将其他类型转换为类类型m1 = e1;return 0;
}
  • eg:P31\03.cpp
#include <iostream>
#include <string>
using namespace std;class Manager;//因为operator Manager() ,所以需要前向声明
class Employee
{
public:Employee(const string& name, const int age, const int deptno) : name_(name),age_(age), deptno_(deptno){}//将Employee转换为Manager类型operator Manager();//下面这样写是错的,因为在这俩类在同一个文件中,只有Manager的前向声明,看不到Manager的定义,也就看不到Manager类的构造函数,error// operator Manager()// {//     return Manager(name_, age_, deptno_, -1);// }private:string name_;int age_;int deptno_;//部门号
};//经理类继承至员工类
class Manager : public Employee
{
public:Manager(const string& name, const int age, const int deptno, int level): Employee(name, age, deptno, level), level_(level)Manager(const Employee& other) : Employee(other), level_(-1) {}
private:int level_;
};//仅仅是从语法上演示基类对象可以转化为派生类对象,但是没有意义
//目的是要理解转换构造函数与类型运算符重载的区别
//把它放在Manager类的定义之后,这样才能看到Manager的构造函数
Employee::operator Manager()
{return Manager(name_, age_, deptno_, -1);//构造Manager对象
}int main(void)
{Employee el("zhangsan", 25, 20);Manager ml("lisi", 38, 20, 10);//方法(2):类型转换运算符重载:将类类型转换为其他类型//将基类对象转换为派生类对象m1 = e1;return 0;
}

这篇关于(P31)继承:转换与继承 ,派生类到基类的转换 ,基类到派生类的转换的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1041384

相关文章

关于C++中的虚拟继承的一些总结(虚拟继承,覆盖,派生,隐藏)

1.为什么要引入虚拟继承 虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继承自类A,因此在类D中两次出现类A中的变量和函数。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类。实现的代码如下: class A class B1:public virtual A; class B2:pu

LangChain转换链:让数据处理更精准

1. 转换链的概念 在开发AI Agent(智能体)时,我们经常需要对输入数据进行预处理,这样可以更好地利用LLM。LangChain提供了一个强大的工具——转换链(TransformChain),它可以帮我们轻松实现这一任务。 转换链(TransformChain)主要是将 给定的数据 按照某个函数进行转换,再将 转换后的结果 输出给LLM。 所以转换链的核心是:根据业务逻辑编写合适的转换函

工程文档CAD转换必备!在 Java 中将 DWG 转换为 JPG

Aspose.CAD 是一个独立的类库,以加强Java应用程序处理和渲染CAD图纸,而不需要AutoCAD或任何其他渲染工作流程。该CAD类库允许将DWG, DWT, DWF, DWFX, IFC, PLT, DGN, OBJ, STL, IGES, CFF2文件、布局和图层高质量地转换为PDF和光栅图像格式。 Aspose API支持流行文件格式处理,并允许将各类文档导出或转换为固定布局文件格

直接得到Json串,转换为字典

0.新创建一个json文件,把json串拷贝到里面 1.先通过MainBundle找到资源对应的路径 2.将文件转换为NSData 3.通过NSJSonSerization得到字典 NSString*fileName=[[NSBundle mainBundle] pathForResource:@"myJson" ofType:@"json"];           NS

第三十七章 添加和使用自定义标题元素 - 自定义标头的继承

文章目录 第三十七章 添加和使用自定义标题元素 - 自定义标头的继承自定义标头的继承示例 在 `SOAPHEADERS` 参数中指定支持的标头元素自定义标头的继承 第三十七章 添加和使用自定义标题元素 - 自定义标头的继承 自定义标头的继承 如果创建此Web 服务的子类,该子类将继承不特定于方法的标头信息 — 包含在 <request> 或 <response> 元素中的标头信

如何通过示例将旧版 C# 转换为 C# 12

随着 C# 的不断发展,每个新版本都会引入强大的新功能,从而提高语言的功能和可读性。通过从旧版本的 C# 迁移到 C# 12,您可以获得更高效、更易于维护和更具表现力的代码。 由于代码库遗留、公司限制以及对旧语言功能的熟悉,许多开发人员仍在使用旧版本的 C#。升级似乎很困难,但现代版本的 C# 具有显著的优势,例如更好的性能、增强的功能和更高的安全性。 通过增量重构、试点项目和团队培训逐步

将知乎专栏文章转换为 Markdown 文件保存到本地

一、参考内容 参考知乎文章`代码 | 将知乎专栏文章转换为 Markdown 文件保存到本地,利用代码为GitHub:https://github.com/chenluda/zhihu-download。 二、步骤 1.首先安装包flask、flask-cors、markdownify 2. 运行app.py 3.在浏览器中打开链接,并填写URL和Cookies 获取Cookies的步

js实现继承的多种方式

1:原型链方式,即子类通过prototype将所有在父类中通过prototype追加的属性和方法都追加到Child,从而实现了继承   function Person(){   }   Person.prototype.hello = "hello";   Person.prototype.sayHello = function(){     alert(this.h

Linux float int和16进制互相转换

Linux 上float int和16进制互换操作。之前把float转16进制,也就是转成4个字节,方便使用串口传输嘛。使用的方法是: //float 转 16进制float x_pid_p = 15.0;unsigned char * bValue = (unsigned char *)& x_pid_p;printf("%x\t%x\t%x\t%x\n", bValue[0], bVa

Day59 代码随想录打卡|二叉树篇---把二叉搜索树转换为累加树

题目(leecode T538): 给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。 提醒一下,二叉搜索树满足下列约束条件: 节点的左子树仅包含键 小于 节点键的节点。节点的右子树仅包含键 大于 节点键的节点。左右子树也必须是二叉搜索树。 方法:本题