C++将派生类赋值给基类(向上转型)

news2024/9/27 21:17:55

1.将派生类对象赋值给基类对象

#include <iostream>
using namespace std;

//基类
class A{
public:
    A(int a);
public:
    void display();
public:
    int m_a;
};
A::A(int a): m_a(a){ }
void A::display(){
    cout<<"Class A: m_a="<<m_a<<endl;
}

//派生类
class B: public A{
public:
    B(int a, int b);
public:
    void display();
public:
    int m_b;
};
B::B(int a, int b): A(a), m_b(b){ }
void B::display(){
    cout<<"Class B: m_a="<<m_a<<", m_b="<<m_b<<endl;
}


int main(){
    A a(10);
    B b(66, 99);
    //赋值前
    a.display();
    b.display();
    cout<<"--------------"<<endl;
    //赋值后
    a = b;
    a.display();
    b.display();

    return 0;
}

运行结果:

Class A: m_a=10
Class B: m_a=66, m_b=99
'----------------------------
Class A: m_a=66
Class B: m_a=66, m_b=99
在这里插入图片描述

2.将派生类指针赋值给基类指针

#include <iostream>
using namespace std;

//基类A
class A{
public:
    A(int a);
public:
    void display();
protected:
    int m_a;
};
A::A(int a): m_a(a){ }
void A::display(){
    cout<<"Class A: m_a="<<m_a<<endl;
}

//中间派生类B
class B: public A{
public:
    B(int a, int b);
public:
    void display();
protected:
    int m_b;
};
B::B(int a, int b): A(a), m_b(b){ }
void B::display(){
    cout<<"Class B: m_a="<<m_a<<", m_b="<<m_b<<endl;
}

//基类C
class C{
public:
    C(int c);
public:
    void display();
protected:
    int m_c;
};
C::C(int c): m_c(c){ }
void C::display(){
    cout<<"Class C: m_c="<<m_c<<endl;
}

//最终派生类D
class D: public B, public C{
public:
    D(int a, int b, int c, int d);
public:
    void display();
private:
    int m_d;
};
D::D(int a, int b, int c, int d): B(a, b), C(c), m_d(d){ }
void D::display(){
    cout<<"Class D: m_a="<<m_a<<", m_b="<<m_b<<", m_c="<<m_c<<", m_d="<<m_d<<endl;
}


int main(){
    A *pa = new A(1);
    B *pb = new B(2, 20);
    C *pc = new C(3);
    D *pd = new D(4, 40, 400, 4000);

    pa = pd;
    pa -> display();

    pb = pd;
    pb -> display();

    pc = pd;
    pc -> display();

    cout<<"-----------------------"<<endl;
    cout<<"pa="<<pa<<endl;
    cout<<"pb="<<pb<<endl;
    cout<<"pc="<<pc<<endl;
    cout<<"pd="<<pd<<endl;

    return 0;
}

运行结果:

Class A: m_a=4
Class B: m_a=4, m_b=40
Class C: m_c=400
'-----------------------
pa=0x9b17f8
pb=0x9b17f8
pc=0x9b1800
pd=0x9b17f8

本例中定义了多个对象指针,并尝试将派生类指针赋值给基类指针。与对象变量之间的赋值不同的是,对象指针之间的赋值并没有拷贝对象的成员,也没有修改对象本身的数据,*仅仅是改变了指针的指向*。
3.virtual实现多态

#include <iostream>
using namespace std;

//基类People
class People{
public:
    People(char *name, int age);
    void display();
protected:
    char *m_name;
    int m_age;
};
People::People(char *name, int age): m_name(name), m_age(age){}
void People::display(){
    cout<<m_name<<"今年"<<m_age<<"岁了,是个无业游民。"<<endl;
}

//派生类Teacher
class Teacher: public People{
public:
    Teacher(char *name, int age, int salary);
    void display();
private:
    int m_salary;
};
Teacher::Teacher(char *name, int age, int salary): People(name, age), m_salary(salary){}
void Teacher::display(){
    cout<<m_name<<"今年"<<m_age<<"岁了,是一名教师,每月有"<<m_salary<<"元的收入。"<<endl;
}

int main(){
    People *p = new People("王志刚", 23);
    p -> display();

    p = new Teacher("赵宏佳", 45, 8200);
    p -> display();

    return 0;
}

在这里插入图片描述

#include <iostream>
using namespace std;

//基类People
class People{
public:
    People(char *name, int age);
    virtual void display();  //声明为虚函数
protected:
    char *m_name;
    int m_age;
};
People::People(char *name, int age): m_name(name), m_age(age){}
void People::display(){
    cout<<m_name<<"今年"<<m_age<<"岁了,是个无业游民。"<<endl;
}

//派生类Teacher
class Teacher: public People{
public:
    Teacher(char *name, int age, int salary);
    virtual void display();  //声明为虚函数
private:
    int m_salary;
};
Teacher::Teacher(char *name, int age, int salary): People(name, age), m_salary(salary){}
void Teacher::display(){
    cout<<m_name<<"今年"<<m_age<<"岁了,是一名教师,每月有"<<m_salary<<"元的收入。"<<endl;
}

int main(){
    People *p = new People("王志刚", 23);
    p -> display();

    p = new Teacher("赵宏佳", 45, 8200);
    p -> display();

    return 0;
}

在这里插入图片描述
4.多态例子:

#include <iostream>
using namespace std;

//军队
class Troops{
public:
    virtual void fight(){ cout<<"Strike back!"<<endl; }
};

//陆军
class Army: public Troops{
public:
    void fight(){ cout<<"--Army is fighting!"<<endl; }
};
//99A主战坦克
class _99A: public Army{
public:
    void fight(){ cout<<"----99A(Tank) is fighting!"<<endl; }
};
//武直10武装直升机
class WZ_10: public Army{
public:
    void fight(){ cout<<"----WZ-10(Helicopter) is fighting!"<<endl; }
};
//长剑10巡航导弹
class CJ_10: public Army{
public:
    void fight(){ cout<<"----CJ-10(Missile) is fighting!"<<endl; }
};

//空军
class AirForce: public Troops{
public:
    void fight(){ cout<<"--AirForce is fighting!"<<endl; }
};
//J-20隐形歼击机
class J_20: public AirForce{
public:
    void fight(){ cout<<"----J-20(Fighter Plane) is fighting!"<<endl; }
};
//CH5无人机
class CH_5: public AirForce{
public:
    void fight(){ cout<<"----CH-5(UAV) is fighting!"<<endl; }
};
//轰6K轰炸机
class H_6K: public AirForce{
public:
    void fight(){ cout<<"----H-6K(Bomber) is fighting!"<<endl; }
};

int main(){
    Troops *p = new Troops;
    p ->fight();
    //陆军
    p = new Army;
    p ->fight();
    p = new _99A;
    p -> fight();
    p = new WZ_10;
    p -> fight();
    p = new CJ_10;
    p -> fight();
    //空军
    p = new AirForce;
    p -> fight();
    p = new J_20;
    p -> fight();
    p = new CH_5;
    p -> fight();
    p = new H_6K;
    p -> fight();

    return 0;
}

在这里插入图片描述
5.dynamic_cast 关键字
dynamic_cast 用于在类的继承层次之间进行类型转换,它既允许向上转型(Upcasting),也允许向下转型(Downcasting)。向上转型是无条件的,不会进行任何检测,所以都能成功;向下转型的前提必须是安全的,要借助 RTTI 进行检测,所有只有一部分能成功。
5.1.向上转型(Upcasting)
向上转型时,只要待转换的两个类型之间存在继承关系,并且基类包含了虚函数(这些信息在编译期间就能确定),就一定能转换成功。因为向上转型始终是安全的,所以 dynamic_cast 不会进行任何运行期间的检查,这个时候的 dynamic_cast 和 static_cast 就没有什么区别了。

#include <iostream>
#include <iomanip>
using namespace std;

class Base{
public:
    Base(int a = 0): m_a(a){ }
    int get_a() const{ return m_a; }
    virtual void func() const { }
protected:
    int m_a;
};

class Derived: public Base{
public:
    Derived(int a = 0, int b = 0): Base(a), m_b(b){ }
    int get_b() const { return m_b; }
private:
    int m_b;
};

int main(){
    //情况①
    Derived *pd1 = new Derived(35, 78);
    Base *pb1 = dynamic_cast<Derived*>(pd1);
    cout<<"pd1 = "<<pd1<<", pb1 = "<<pb1<<endl;
    cout<<pb1->get_a()<<endl;	//OK
    cout<<pb1->get_b()<<endl;	//NG
    cout<<pd1->get_b()<<endl;	//OK
    pb1->func();

    return 0;
}

5.2.向下转型(Downcasting)
向下转型是有风险的,dynamic_cast 会借助 RTTI 信息进行检测,确定安全的才能转换成功,否则就转换失败。那么,哪些向下转型是安全地呢,哪些又是不安全的呢?下面我们通过一个例子来演示:

#include <iostream>
using namespace std;

class A{
public:
    virtual void func() const { cout<<"Class A"<<endl; }
private:
    int m_a;
};

class B: public A{
public:
    virtual void func() const { cout<<"Class B"<<endl; }
private:
    int m_b;
};

class C: public B{
public:
    virtual void func() const { cout<<"Class C"<<endl; }
private:
    int m_c;
};

class D: public C{
public:
    virtual void func() const { cout<<"Class D"<<endl; }
private:
    int m_d;
};

int main(){
    A *pa = new A();
    B *pb;
    C *pc;
   
    //情况①
    pb = dynamic_cast<B*>(pa);  //向下转型失败
    if(pb == NULL){
        cout<<"Downcasting failed: A* to B*"<<endl;
    }else{
        cout<<"Downcasting successfully: A* to B*"<<endl;
        pb -> func();
    }
    pc = dynamic_cast<C*>(pa);  //向下转型失败
    if(pc == NULL){
        cout<<"Downcasting failed: A* to C*"<<endl;
    }else{
        cout<<"Downcasting successfully: A* to C*"<<endl;
        pc -> func();
    }
   
    cout<<"-------------------------"<<endl;
   
    //情况②
    pa = new D();  //向上转型都是允许的
    pb = dynamic_cast<B*>(pa);  //向下转型成功
    if(pb == NULL){
        cout<<"Downcasting failed: A* to B*"<<endl;
    }else{
        cout<<"Downcasting successfully: A* to B*"<<endl;
        pb -> func();
    }
    pc = dynamic_cast<C*>(pa);  //向下转型成功
    if(pc == NULL){
        cout<<"Downcasting failed: A* to C*"<<endl;
    }else{
        cout<<"Downcasting successfully: A* to C*"<<endl;
        pc -> func();
    }
   
    return 0;
}

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/375944.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文解读电压放大器(电压放大器原理)

关于电压放大器的科普知识&#xff0c;之前讲过很多&#xff0c;今天为大家汇总一篇文章来详细的讲解电压放大器&#xff0c;希望大家对于电压放大器能有更清晰的认识。电压放大器是什么&#xff1a;电压放大器是一种常用的电子器件&#xff0c;它的主要作用是把输入信号的振幅…

计算机网络-- 分类、体系结构(day03)

计算机网络的分类 计算机网络的性能指标 速率 数据块&#xff08;文件&#xff09;的大小单位是以2^10(1024)为一个级别递增。 例如&#xff1a; 1MB大小的文件&#xff0c;在网速为1Mbps发送的时间需要多少 文件大小的M是2进制来表示的&#xff0c;网速的M为10进制来表示的 …

zabbix4.0-自定义脚本钉钉告警

目录 1、自定义一个钉钉群组 2、自定义脚本告警 3、创建媒体类型 4、为用户指定媒介类型 5、更改触发器表达式进行测试 1、自定义一个钉钉群组 群组里面添加一个自定义机器人 会有一个webhook地址&#xff0c;这个地址要记住 安全设置暂时选择自定义关键词&#xff0c;定义…

第四阶段02-酷鲨商城项目Mybatis相关的配置

14. 添加与Mybatis相关的配置 在每个项目中&#xff0c;当需要使用Mybatis实现数据库编程时&#xff0c;都需要添加2项一次性配置&#xff1a;配置Mapper接口所在的包&#xff08;package&#xff09;、配置XML文件在哪里。 关于配置Mapper接口所在的包&#xff0c;可以&…

BPMN2.0是什么,BPMN能解决企业流程管理中哪些问题?

一、前言&#xff1a; 在任何行业和企业中&#xff0c;一定存在着各式各样的流程&#xff0c;请假流程、报销流程、入职流程、离职流程、出差流程、合同审批流程、出入库流程等等…… 无论是管理者、技术人员还是业务人员&#xff0c;每天肯定也在使用各种流程&#xff0c;但…

《MySQL学习》 索引失效的三种特殊情况

一.条件字段使用函数 explain select * from bpm_proc_instance bpi where CREATED_AT > 2022-06-01 CREATED_AT 字段建立了索引&#xff0c;此时explain分析的结果表明能使用到索引 但如果我们对 CREATED_AT 字段使用函数 explain select * from bpm_proc_instance bpi w…

【强烈建议收藏:计算机网络面试专题:URL地址栏中输入网址到页面展示的全过程DNS域名解析的过程】

一.面试官:我们就来问一下关于计算机网络相关的专业知识吧 面试官:好的&#xff0c;那我们yyyy-mm-dd就在腾讯会议上面试吧; 卑微的你:好的。 卑微的你:到了面试的时间了&#xff0c;守时的你一定早早的进入了视频会议&#xff0c;等待着面试官&#xff0c;心里慌的一批&#…

Elasticsearch7.8.0版本进阶——文档处理

目录一、文档冲突1.1、文档冲突的概述1.2、在数据库领域中如何确保并发更新时变更不会丢失1.2.1、悲观并发控制1.2.2、乐观并发控制二、乐观并发控制2.1、Elasticsearch 的概述2.2、Elasticsearch 如何确保文档的旧版本不会覆盖新的版本2.3、Elasticsearch 如何解决相互冲突的变…

洛谷P5738 【深基7.例4】歌唱比赛 C语言/C++

【深基7.例4】歌唱比赛 题目描述 n(n≤100)n(n\le 100)n(n≤100) 名同学参加歌唱比赛&#xff0c;并接受 m(m≤20)m(m\le 20)m(m≤20) 名评委的评分&#xff0c;评分范围是 000 到 101010 分。这名同学的得分就是这些评委给分中去掉一个最高分&#xff0c;去掉一个最低分&…

拍摄的风景视频中,如何快速有效地去除视频中的杂物?

我们在外游玩拍摄的短视频&#xff0c;视频中出现的不必要杂物&#xff0c;比如垃圾、广告或其他不相关的人&#xff0c;会影响视频内容的传达&#xff0c;会降低视频的观感质量。因此&#xff0c;需要去除这些杂物&#xff0c;使得视频更加干净、整洁。让观众更容易理解视频的…

性能分析工具的使用

在数据库调优中&#xff0c;我们的目标就是响应时间更快&#xff0c;吞吐量更大。利用宏观的监控工具和微观的日志分析可以帮我们快速找到调优的思路和方式。 1.数据库服务器优化步骤 数据库调优流程图 整个流程划分成了**观察(Show status&#xff09;和行动&#xff08;Ac…

行测-判断推理-图形推理-样式规律-属性规律-曲直性

左边的图全是由曲线构成的选C1 3 5全是由曲线构成的2 4 6全是由直线构成的第三行的图形有曲有直选A1 3 5有曲有直2 4 6全是直线选D图形有曲有直&#xff0c;排除B D外曲内直->内曲外直->外曲内直->内曲外直->外曲内直->内曲外直所以问号出的图形应该是内曲外直选…

【面试题】当面试官问 Vue2与Vue3的区别,你该怎么回答?

大厂面试题分享 面试题库后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★地址&#xff1a;前端面试题库被问到 《vue2 与 vue3 的区别》应该怎么回答Vue 内部根据功能可以被分为三个大的模块&#xff1a;响应性 reactivite、运行时 runtime、编辑器…

Win11 文件夹打开慢或卡顿解决方案

问题 目前是 2023/2/27, 我的 Win11 系统点开一个文件夹要等待 2-3 秒才能加载出来, 使用体验极差。网上查阅大量资料, 有些人在系统更新后这个情况就消失了, 但是我这一直存在, 系统也是当前的最新版, 没有修复。 目前得出的结论是, 因为 Win11 的工具栏占用了过多的资源, 需…

Web3中文|Litra:简洁而优美的NFT流动性协议,能给NFT市场带来什么?

2021年&#xff0c;NFT元年2021年&#xff0c;无疑是 NFT 的“元年”。这一年推特创始人的首条推特被拍出250万美元&#xff0c;加密艺术家Beeple的数字作品“First 5000 Days”在佳士得以6900万美元价格成交&#xff0c;无聊猿最高上涨了1800倍。2021年11月&#xff0c;在Goog…

【Python学习笔记】第十九节 Python 面向对象(一)

在现实世界中&#xff0c;随处可见的一种事物就是对象&#xff0c;对象是事物存在的实体&#xff0c;如学生、汽车等。人类解决问题的方式总是将复杂的事物简单化&#xff0c;于是就会思考这些对象都是由哪些部分组成的。通常都会将对象划分为两个部分&#xff0c;即静态部分与…

一文让你上手shell

简介shell是C 语言编写的程序&#xff0c;是向操作访问Linux内核的桥梁。shell也是测试人员需要简单必备的一项小技能&#xff0c;至少能看懂并简单编写脚本&#xff0c;可以让与Linux相关的操作提升1个level。扩展名&#xff1a;.sh运行操作系统&#xff1a;Linux运行环境&…

cesium从入门到进阶(一):坐标系与坐标系转换

目录 一、坐标系 1、屏幕坐标系(像素) 1.1 二维笛卡尔平面坐标Cartesian2 1.2 三维笛卡尔空间坐标(世界坐标)Cartesian3 2、地理坐标系 2.1 地理坐标系&#xff08;弧度&#xff09;Cartographic 2.2 地理坐标系&#xff08;经纬度&#xff09;WGS84 二、坐标系转换 1…

华为不丢失数据解手机屏幕锁华为售后能保资料解锁吗华为锁屏保留数据荣耀手机解锁保数据华为手机保存数据解锁

大家好&#xff0c;今天给大家分享的华为mate9手机忘记密码保资料不清除数据解锁华为手机案例分享&#xff1a;这个用户是从马来西亚邮递回国的华为p30手机进行保资料不清除数据解除华为锁屏密码&#xff0c;由于机主突然的去世&#xff0c;手机里有公司贵重的资料&#xff0c;…

27 openEuler管理网络-通过ifcfg文件配置网络

文章目录27 openEuler管理网络-通过ifcfg文件配置网络27.1 配置静态网络27.2 配置动态网络27.3 配置默认网关27 openEuler管理网络-通过ifcfg文件配置网络 说明&#xff1a; 通过ifcfg文件配置的网络配置不会立即生效&#xff0c;需要在root权限下执行systemctl reload Network…