C++基础之继承续(十六)

一.基类与派生类之间的转换

  1. 可以把派生类赋值给基类
  2. 可以把基类引用绑定派生类对象
  3. 可以把基类指针指向派生类对象
#include <iostream>

using std::cin;
using std::cout;
using std::endl;

//基类与派生类相互转化
class Base
{
private:
    int _x;
public:
    Base(int x=0)
    :_x(x)
    {
        cout<<"Base()"<<endl;
    }
    ~Base()
    {
        cout<<"~Base()"<<endl;
    }
    void show()
    {
        cout<<"_x ="<<_x<<endl;
    }
};

class Derived

:public Base
{

private:
    int _y;

public:
    Derived(int x=0,int y=0)
    :Base(x)
    ,_y(y)
    {
        cout<<"Derived()"<<endl;
    }
    ~Derived()
    {
        cout<<"~Derived()"<<endl;
    }

    void show()
    {
        cout<<"_y ="<<_y<<endl;
    }
};

void test()
{
    Base base(3);
    Derived derived(5,4);

    derived.show();
    base.show();
    cout<<"派生类向基类转换"<<endl;
   
    base=derived;
    base.show();
    derived.show();

    Base& base1=derived;
    Base* base2=&derived;
    base1.show(); 
    base2->show();

    Base base3=derived;

}

int main()
{
    test();
    return 0;

}

当派生类转换为基类时,派生类将初始完基类的数据成员再赋给基类。如果需要将基类转换为派生类需要加强制类型转换。

二.派生类间的复制控制

        如果基类实现了拷贝构造函数或赋值运算符函数,但是派生类没有实现拷贝构造函数或赋值运算符函数,那么在将一个已经存在的派生类对象初始化一个刚刚创建的派生类对象会调用拷贝构造函数,或者进行两个对象进行赋值时调用赋值运算符函数,由于派生类没有拷贝构造函数那么派生部分就会执行缺省行为,而基类部分会调用基类的构造函数和赋值运算符函数。

1.当派生类无新数据成员时

#include <iostream>
#include <string.h>
using std::cout;
using std::endl;

class Base
{
private:
    char* _pbase;
public:
    Base(const char* str)
    :_pbase(new char[strlen(str)+1]())
    {
        cout<<"Base(const char* str)"<<endl;
        strcpy(_pbase,str);
    }
    ~Base()
    {
        cout<<"~Base()"<<endl;
        if(_pbase!=nullptr)
        {
            delete[]_pbase;
            _pbase=nullptr;
        }
    }
    Base()
    :_pbase(nullptr)
    {
        cout<<"Base()"<<endl;
    }
    Base(const Base& rhs)
    :_pbase(new char[strlen(rhs._pbase)+1]())
    {
        cout<<"Base(const Base& rhs)"<<endl;
        strcpy(_pbase,rhs._pbase);
    }

    Base& operator=(const Base& rhs)
    {
        //自复制
        if(this != &rhs)
        {
            cout<<"Base& operator=(const Base& rhs)"<<endl;
            if(_pbase!=nullptr)
            {
                delete[] _pbase;
                _pbase=nullptr;
            }
            _pbase=new char[strlen(rhs._pbase)+1]();
            strcpy(_pbase,rhs._pbase);
        }
        return *this;
    }
    friend std::ostream& operator<<(std::ostream& os,const Base& rhs);
    
};

class Derived
: public Base
{

public:
    Derived(const char* str1)
    :Base(str1)
    {
        cout<<"Derived(const char* str1)"<<endl;
    }

    ~Derived()
    {
        cout<<"~Derived()"<<endl;
    }

    friend std::ostream& operator<<(std::ostream& os,const Derived& rhs);
};

std::ostream& operator<<(std::ostream& os,const Derived& rhs)
{
    const Base &base=rhs;
    os<<base;
    return os;
}
std::ostream& operator<<(std::ostream& os,const Base& rhs)
{
    if(rhs._pbase)
    {
        os<<rhs._pbase;
    }
    return os;
}

void test()
{
    Derived derived("hello");
    cout<<"derived = "<<derived<<endl;
    cout<<endl;

    Derived derived1(derived);
    cout<<"derived = "<<derived<<endl;
    cout<<"derived1 = "<<derived1<<endl;

    cout<<endl;
    Derived derived2("你好");
    cout<<"derived2 = "<<derived2<<endl;
    cout<<endl;

    derived2=derived;
    cout<<"derived = "<<derived<<endl;
    cout<<"derived2 = "<<derived2<<endl;
}

int main()
{
    test();
    return 0;
}

2.当派生类有新数据成员时

#include <iostream>
#include <string.h>
using std::cout;
using std::endl;

class Base
{
private:
    char* _pbase;
public:
    Base(const char* str)
    :_pbase(new char[strlen(str)+1]())
    {
        cout<<"Base(const char* str)"<<endl;
        strcpy(_pbase,str);
    }
    ~Base()
    {
        cout<<"~Base()"<<endl;
        if(_pbase!=nullptr)
        {
            delete[]_pbase;
            _pbase=nullptr;
        }
    }
    Base()
    :_pbase(nullptr)
    {
        cout<<"Base()"<<endl;
    }
    Base(const Base& rhs)
    :_pbase(new char[strlen(rhs._pbase)+1]())
    {
        cout<<"Base(const Base& rhs)"<<endl;
        strcpy(_pbase,rhs._pbase);
    }
    Base& operator=(const Base& rhs)
    {
        //自复制
        if(this != &rhs)
        {
            cout<<"Base& operator=(const Base& rhs)"<<endl;
            if(_pbase!=nullptr)
            {
                delete[] _pbase;
                _pbase=nullptr;
            }
            _pbase=new char[strlen(rhs._pbase)+1]();
            strcpy(_pbase,rhs._pbase);
        }
        return *this;
    }
    friend std::ostream& operator<<(std::ostream& os,const Base& rhs);
};

class Derived
: public Base
{
private:
    char* _pderived;
public:
    Derived(const char* str1,const char* str2)
    :Base(str1)
    ,_pderived(new char[strlen(str2)+1]())
    {
        cout<<"Derived(const char* str1,const char* str2)"<<endl;
        strcpy(_pderived,str2);
    }
    Derived(const Derived& rhs)
    :_pderived(new char[strlen(rhs._pderived)+1]())
    {
        cout<<"Derived(const Derived& rhs)"<<endl;
        strcpy(_pderived,rhs._pderived);
    }

    Derived& operator=(const Derived& rhs)
    {
        cout<<"Derived& operator=(const Derived& rhs)"<<endl;
        if(this != &rhs)
        {
            if(_pderived!=nullptr)
            {
                delete[]_pderived;
                _pderived=nullptr;
            }
            _pderived=new char[strlen(rhs._pderived)+1]();
            strcpy(_pderived,rhs._pderived);
        }
        return *this;
    }

    ~Derived()
    {
        cout<<"~Derived()"<<endl;
        if(_pderived!=nullptr)
        {
            delete[]_pderived;
            _pderived=nullptr;
        }
    }

    friend std::ostream& operator<<(std::ostream& os,const Derived& rhs);   
};

std::ostream& operator<<(std::ostream& os,const Derived& rhs)
{
    const Base &base=rhs;
    os<<base<<" , "<<rhs._pderived;
    return os;
}
std::ostream& operator<<(std::ostream& os,const Base& rhs)
{
    if(rhs._pbase)
    {
        os<<rhs._pbase;
    }
    return os;
}
void test()
{
    Derived derived("hello","world");
    cout<<"derived = "<<derived<<endl;
    cout<<endl;

    Derived derived1(derived);
    cout<<"derived = "<<derived<<endl;
    cout<<"derived1 = "<<derived1<<endl;

    cout<<endl;
    Derived derived2("你好","世界");
    cout<<"derived2 = "<<derived2<<endl;
    cout<<endl;

    derived2=derived;
    cout<<"derived = "<<derived<<endl;
    cout<<"derived2 = "<<derived2<<endl;
}

int main()
{
    test();
    return 0;
}

        如果基类和派生类都实现了拷贝构造函数和赋值运算符函数,那么在将一个已经存在的派生类对象初始化一个刚刚创建的派生类对象,或者两个派生类对象进行赋值时,派生类数据成员部分会执行派生类自己的拷贝构造函数或赋值运算符函数,而基类部分不会执行基类的拷贝构造函数或赋值运算符函数,除非在派生类中显示的调用基类的拷贝与赋值。

3.改进

#include <iostream>
#include <string.h>
using std::cout;
using std::cin;
using std::endl;

class Base
{
private:
    char* _pbase;
public:
    Base(const char* str)
    :_pbase(new char[strlen(str)+1]())
    {
        cout<<"Base(const char* str)"<<endl;
        strcpy(_pbase,str);
    }
    ~Base()
    {
        cout<<"~Base()"<<endl;
        if(_pbase!=nullptr)
        {
            delete[]_pbase;
            _pbase=nullptr;
        }
    }
    Base()
    :_pbase(nullptr)
    {
        cout<<"Base()"<<endl;
    }
    Base(const Base& rhs)
    :_pbase(new char[strlen(rhs._pbase)+1]())
    {
        cout<<"Base(const Base& rhs)"<<endl;
        strcpy(_pbase,rhs._pbase);
    }

    Base& operator=(const Base& rhs)
    {
        //自复制
        if(this != &rhs)
        {
            cout<<"Base& operator=(const Base& rhs)"<<endl;
            if(_pbase!=nullptr)
            {
                delete[] _pbase;
                _pbase=nullptr;
            }
            _pbase=new char[strlen(rhs._pbase)+1]();
            strcpy(_pbase,rhs._pbase);
        }
        return *this;
    }
    friend std::ostream& operator<<(std::ostream& os,const Base& rhs);
    
};



class Derived
: public Base
{
private:
    char* _pderived;
public:
    Derived(const char* str1,const char* str2)
    :Base(str1)
    ,_pderived(new char[strlen(str2)+1]())
    {
        cout<<"Derived(const char* str1,const char* str2)"<<endl;
        strcpy(_pderived,str2);
    }
    Derived(const Derived& rhs)
    :Base(rhs)    //显示调用拷贝构造函数
    ,_pderived(new char[strlen(rhs._pderived)+1]())
    {
        cout<<"Derived(const Derived& rhs)"<<endl;
        strcpy(_pderived,rhs._pderived);
    }

    Derived& operator=(const Derived& rhs)
    {
        cout<<"Derived& operator=(const Derived& rhs)"<<endl;
        Base::operator=(rhs);//显示调用赋值运算符函数
        if(this != &rhs)
        {
            if(_pderived!=nullptr)
            {
                delete[]_pderived;
                _pderived=nullptr;
            }
            _pderived=new char[strlen(rhs._pderived)+1]();
            strcpy(_pderived,rhs._pderived);
        }
        return *this;
    }

    ~Derived()
    {
        cout<<"~Derived()"<<endl;
        if(_pderived!=nullptr)
        {
            delete[]_pderived;
            _pderived=nullptr;
        }
    }

    friend std::ostream& operator<<(std::ostream& os,const Derived& rhs);
    
};

std::ostream& operator<<(std::ostream& os,const Derived& rhs)
{
    const Base &base=rhs;
    os<<base<<" , "<<rhs._pderived;
    return os;
}
std::ostream& operator<<(std::ostream& os,const Base& rhs)
{
    if(rhs._pbase)
    {
        os<<rhs._pbase;
    }
    return os;
}

void test()
{
    Derived derived("hello","world");
    cout<<"derived = "<<derived<<endl;
    cout<<endl;

    Derived derived1(derived);
    cout<<"derived = "<<derived<<endl;
    cout<<"derived1 = "<<derived1<<endl;

    cout<<endl;
    Derived derived2("你好","世界");
    cout<<"derived2 = "<<derived2<<endl;
    cout<<endl;

    derived2=derived;
    cout<<"derived = "<<derived<<endl;
    cout<<"derived2 = "<<derived2<<endl;

}

int main()
{
    test();
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(执行上下文作用域链)前端八股文修炼Day4

一 作用域作用域链 作用域&#xff08;Scope&#xff09;是指程序中定义变量的区域&#xff0c;作用域规定了在这个区域内变量的可访问性。在 JavaScript 中&#xff0c;作用域可以分为全局作用域和局部作用域。 全局作用域&#xff1a;在代码中任何地方都可以访问的作用域&am…

systemd-journal(一)之journalctl命令详解

文章目录 写在前面概述描述不传递参数传递一个或多个匹配参数示例 源选项用法--system, --user-M, --machine-m, --merge-D DIR, --directoryDIR--fileGLOB--rootROOT--imageIMAGE--image-policypolicy--namespaceNAMESPACE 过滤选项用法-S, --since, -U, --until举例&#xff…

Navicat15安装教程

直接开始Navicat15的安装教程 下载好上面的资源&#xff0c;解压后得到以下文件 1. 安装 Navicat ①双击 navicat150_premium_cs_x64.exe&#xff0c;准备安装 Navicat 15 ②无脑一直下一步就行&#xff0c;到下图画面就安装成功了。 2.安装完成以后&#xff0c;先不要启动…

力扣--并查集1631.最小体力消耗路径

这题将图论和并查集联系起来。把数组每个位置看成图中的一个节点。 这段代码的主要思路是&#xff1a; 遍历地图中的每个节点&#xff0c;将每个节点与其相邻的下方节点和右方节点之间的边加入到边集合中&#xff08;因为从上到下和从下到上他们高度绝对值一样的&#xff0c;…

浅谈如何自我实现一个消息队列服务器(3)—— 细节分析

文章目录 2.2 消息存储在文件时涉及到的流对象2.3 序列化、反序列化的方法2.3.1 JSON的ObjectMapper2.3.2 ObjectOutputStream 、 ObjectInputStream2.3.3 第三方库的Hessian2.3.4 protobuffer2.3.5 thrift 2.4 使用类MessageFileManager封装文件存储操作2.4.1 sendMessage()实…

【保姆级讲解Edge兼容性问题解决方法】

&#x1f308;个人主页:程序员不想敲代码啊&#x1f308; &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家&#x1f3c6; &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d; 希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提…

【JavaScript】JavaScript 程序流程控制 ⑦ ( do-while 循环概念 | do-while 循环语法结构 )

文章目录 一、while 循环1、while 循环概念2、do-while 循环语法结构 二、do-while 循环代码示例1、打印 1-5 数字2、打印 1-10 累加和 一、while 循环 1、while 循环概念 JavaScript 中的 do-while 循环 是 while 循环的变体 , 是 一种 后测试 循环 , 该循环的 循环体 至少执行…

Windows系统安装PyTorch框架支持AMD Radeon显卡/Intel显卡

前言 PyTorch框架作为一种主流的、对新手友好的深度学习框架&#xff0c;应用的范围越来越广泛&#xff0c;但是作为一种深度学习框架&#xff0c;使用显卡进行加速训练是一种常见的需求&#xff0c;而PyTorch框架官方支持对NVIDIA卡支持更加友好&#xff0c;这一点从官方的安…

fastadmin学习01-windows下安装部署

下载源代码 官网 安装 解压&#xff0c;然后使用phpstorm打开 修改配置文件 创建数据库 -- drop database fastadmin01; create database fastadmin01;这样fastadmin就部署好了 访问主页也能看到前台页面

什么是 SD-WAN 云端部署?

SD-WAN&#xff08;软件定义广域网&#xff09;是一种网络架构&#xff0c;可以通过软件定义和控制来管理广域网连接&#xff0c;提高网络的灵活性、可靠性和安全性。而SD-WAN的云端部署则是将SD-WAN 解决方案部署在云端环境中&#xff0c;利用云计算的优势来实现网络管理和优化…

MySQL详细教程

文章目录 前言一、数据库管理1.查看已有的数据库2.创建数据库3.删除数据库4.进入数据库 二、 数据表管理1.查看当前数据库下的所有数据表2.创建数据表3.删除表4.查看表结构 三、常用数据类型1.整型tinyintintbigint 2.浮点型floatdoubledecimal 3.字符型char(m)varchar(m)textm…

错误 LNK1104 无法打开文件“mfc140.lib”

如图&#xff0c;编译一个别人已有的项目&#xff0c;我的编译报错为&#xff1a; 但是我所有文件夹全局搜索了一下&#xff0c;这个文件是存在的。但是当前项目访问不到。 更改方法&#xff1a;项目->属性->配置属性->VC目录->库目录 全局搜索找到mfc140.lib的…

【工具篇】总结比较几种绘画软件的优缺点

目录 一、Visio二、Processon三、draw.io四、亿图图示五、wps 写在文章开头&#xff0c;感谢你的支持与关注&#xff01;小卓的主页 一、Visio Visio 是微软公司开发的一款流程图和图表绘制软件。我们可以用它来创建各种类型的图表&#xff0c;如流程图、组织结构图、网络图、平…

计算机基础--发展史

1进化史 计算工具&#xff0c;机械计算机&#xff0c;电子计算机&#xff08;目前&#xff09; 1.1计算工具 1算筹&#xff0c;算盘&#xff08;这些都是计算工具&#xff0c;算数还是得靠大脑算 &#xff09; 2机械计算机 2.1帕斯卡计算器 2.2莱布尼茨乘法器 2.3Curta计数…

聚类分析|基于层次的聚类方法及其Python实现

聚类分析|基于层次的聚类方法及其Python实现 0. 基于层次的聚类方法1. 簇间距离度量方法1.1 最小距离1.2 最大距离1.3 平均距离1.4 中心法1.5 离差平方和 2. 基于层次的聚类算法2.1 凝聚&#xff08;Agglomerative&#xff09;2.3 分裂&#xff08;Divisive&#xff09; 3. 基于…

【蓝桥杯】tarjan算法

一.概述 Tarjan 算法是基于DFS的算法&#xff0c;用于求解图的连通性问题。 Tarjan 算法可以在线性时间内求出&#xff1a; 无向图&#xff1a; 割点与桥双连通分量 有向图&#xff1a; 强连通分量必经点与必经边 1.割点&#xff1a; 若从图中删除节点 x 以及所有与 x 关联的…

【Java项目】jspm九宫格日志网站

目录 背景 技术简介 系统简介 界面预览 背景 互联网的迅猛发展彻底转变了全球各类组织的管理策略。自20世纪90年代起&#xff0c;中国的政府机关和各类企业便开始探索利用互联网技术来处理管理信息。然而&#xff0c;由于当时网络覆盖不广、用户接受度不高、互联网法律法规…

一文说清:AI大模型在制造业中的应用类型

在过去的几年里&#xff0c;全球制造业的竞争格局正在发生重构&#xff0c;数字化和智能化成为推动变革的关键力量。AI 大模型作为一种通用人工智能技术&#xff0c;其革命性特征体现在能够生成代码、构建人机交互新模式&#xff0c;并与产品研发、工艺设计、生产作业、产品运营…

羊大师解析,孩子喝羊奶的好处

羊大师解析&#xff0c;孩子喝羊奶的好处 孩子喝羊奶有诸多好处。羊奶富含多种营养物质&#xff0c;包括蛋白质、脂肪、维生素和矿物质等&#xff0c;对孩子的生长发育和身体健康都有积极的促进作用。羊奶中的蛋白质含量丰富&#xff0c;且易于消化吸收。这些优质蛋白质可以为…

《海王2》观后感

前言 我原本计划电影上映之后&#xff0c;去电影院观看的&#xff0c;但时间过得飞快&#xff0c;一眨眼这都快4月份了&#xff0c;查了一下&#xff0c;电影院早就没有排片了&#xff0c;所以只能在B站看了&#xff0c;这里不得不吐槽一下&#xff0c;原来花了4块钱购买观看还…