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

news2024/11/13 13:24:40

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

  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;
}

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

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

相关文章

【Java多线程(2)】Thread常见方法和线程状态

目录 一、Thread类及常见方法 1. join() 等待一个线程 2. currentThread() 获取当前线程引用 3. sleep() 休眠当前线程 二、线程的状态 1. 线程的所有状态 2. 状态转移 一、Thread类及常见方法 接上文&#xff1a;多线程&#xff08;1&#xff09;http://t.csdnimg.cn/…

Docker 【安装MongoDB】

文章目录 前言一、安装二、使用1. 通过权限认证的方式登入2. 基础操作 前言 MongoDB是一个非关系型数据库&#xff0c;它主要的应用场景有这些 相比mysql&#xff0c;MongoDB没有事务&#xff0c;索引之类的东西。最小单位是文档。 可能有人说&#xff0c;为什么这个场景我要…

【无标题】如何使用 MuLogin 设置代理

如何使用 MuLogin 设置代理 使用 MuLogin 浏览器设置我们的代理&#xff0c;轻松管理多个社交媒体或电子商务帐户。 什么是MuLogin&#xff1f; MuLogin 是一款虚拟反检测浏览器&#xff0c;使用户能够管理多个电子商务、社交媒体和广告帐户&#xff0c;而无需验证码或 IP 禁…

canvas画带透明度的直线和涂鸦

提示&#xff1a;canvas画线 文章目录 前言一、带透明度的直线和涂鸦总结 前言 一、带透明度的直线和涂鸦 test.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content…

Chrome浏览器修改网页内容

方法一&#xff1a;使用开发者工具 在Chrome浏览器中打开要修改的网页。按下F12键打开开发者工具。在开发者工具窗口中&#xff0c;找到“Elements”标签页。在“Elements”标签页中&#xff0c;找到要修改的网页元素。双击要修改的网页元素&#xff0c;即可进行编辑。 方法二…

轻松掌握:使用 API 接口自动缩短网址的秘诀

在互联网的世界里&#xff0c;网址缩短已经成为了一种时尚和必要。长而复杂的网址不仅难以记忆&#xff0c;还可能让人望而却步。但是&#xff0c;现在有了 API 接口&#xff0c;我们可以轻松地将网址自动缩短&#xff0c;让分享变得更加简单和高效&#xff01;本文将以具体例子…

Protocol Buffers设计要点

概述 一种开源跨平台的序列化结构化数据的协议。可用于存储数据或在网络上进行数据通信。它提供了用于描述数据结构的接口描述语言&#xff08;IDL&#xff09;&#xff0c;也提供了根据 IDL 产生代码的程序工具。Protocol Buffers的设计目标是简单和性能&#xff0c;所以与 XM…

vue脚手架创建项目:账号登录(利用element-ui快速开发)(取消eslint强制格式)(修改端口号)

新手看不懂&#xff0c;老手不用看系列 文章目录 一、准备工作1.1 取消强制格式检查1.2 导入依赖&#xff0c;注册依赖 二、去element-ui官网找样式写Login组件2.1 引用局部组件2.2 运行项目 三、看一下发现没问题&#xff0c;开始修改前端的代码四、修改端口号4.1 修改后端端口…

Redis 之死:Garantia Data 如何策划了开源史上最大劫案?

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Temple of Doom靶场nodejs获取shellss-manager漏洞tcpdump提权

下载链接&#xff1a; Temple of Doom: 1 ~ VulnHub 下载完成后直接在vxbox中导入即可&#xff0c;网络链接模式根据自身情况而定&#xff08;我采用的桥接模式&#xff09; 正文&#xff1a; 先用nmap进行扫描靶机ip nmap -sn 192.168.1.1/24 对192.168.1.5进行端口探测&a…

Spring学习——什么是循环依赖及其解决方式

文章目录 前言一、什么是循环依赖二、解决思路1、循环依赖分类2、对象初始化步骤及对象分类3、spring是如何解决的4、图解5、三级缓存1、区别2、ObjectFactory是什么 三、源码debug1、spring创建对象过程1、dubug第一步——找到getBean2、dubug第二步——getBean与doGetBean3、…

基于AT89C51单片机的智能交通灯设计

点击链接获取Keil源码与Project Backups仿真图&#xff1a; https://download.csdn.net/download/qq_64505944/89035863?spm1001.2014.3001.5503 1绪 论 1.1课题研究背景 交通是城市经济活动的命脉&#xff0c;对城市经济发展、人民生活水平的提高起着十分重要的作用。城市交…

用 C++ 编码架构图的最佳用例

统一建模语言&#xff08;UML&#xff09;&#xff0c;作为一种实际应用的语言标准&#xff0c;借助一系列架构图呈现建模软件系统。UML 的出现鼓励了自动化软件工具的开发&#xff0c;有助于自动代码生成。UML 图面向对象系统和软件工具&#xff0c;将静态结构和动态行为以可视…

如何统计代码量

工具&#xff1a; cloc 下载地址&#xff1a; Releases AlDanial/cloc GitHub 使用方法&#xff1a;

2024.3.26

实现闹钟 weiget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTimer> #include<QTime> #include<QTimerEvent> #include<QString> #include<QtTextToSpeech> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } Q…

力扣● 503.下一个更大元素II ● 42. 接雨水

503.下一个更大元素II 与496.下一个更大元素 I的不同是要循环地搜索元素的下一个更大的数。那么主要是对于遍历结束后&#xff0c;单调栈里面剩下的那些元素。 如果直接把两个数组拼接在一起&#xff0c;然后使用单调栈求下一个最大值就可以。 代码实现的话&#xff0c;不用直…

ubuntu22.04配置Azure Kinect DK深度相机

一.安装SDK 今天我来配置一下微软公司的Azure Kinect DK深度相机,以前在ubuntu18.04上配置过,因为官方说唯一支持linux版本是18.04,所以在18.04中配置还算顺利 but这不代表不可以在更高版本的ubuntu中使用,只不过需要自己去多配置一些东西 apt 源安装 更新源: c…

上海企业必应bing国内广告推广如何开户?

随着数字化营销时代的深入发展&#xff0c;搜索引擎广告已成为众多企业提升品牌知名度和促进产品销售的重要手段之一。在国内市场&#xff0c;微软必应&#xff08;Bing&#xff09;搜索广告以其精准定位与高价值用户群赢得了众多企业的青睐。对于位于上海地区的企业来说&#…

蓝桥杯:Python基础学习一

目录 一、遍历列表 1.使用for 循环和 enumerate()函数实现 2.案例代码 二、对列表进行统计和计算 1.统计数值列表的元素和 2.案例代码 三、对列表进行排序 1.使用列表对象的sort()方法 2.使用内置的 sorted()函数实现 四、列表推导式 1.从列表中选择符合条件的元素组…

flask_restful结合蓝图使用

在蓝图中&#xff0c;如果使用 Flask_RESTful &#xff0c; 创建 Api 对象的时候&#xff0c;传入蓝图对象即可&#xff0c;不再是传入 app 对象 /user/__init__.py from flask.blueprints import Blueprintuser_bp Blueprint(user,__name__)from user import views /user…