C++面向对象程序设计-北京大学-郭炜【课程笔记(六)】

C++面向对象程序设计-北京大学-郭炜【课程笔记(六)】

  • 1、可变长数组类的实现
  • 2、流插入运算符和流提取运算符的重载
    • 2.1、对形如cout << 5 ; 单个"<<"进行重载
    • 2.2、对形如cout << 5 << “this” ;连续多个"<<"进行重载
    • 详解案例

毕业论文:学习速度较慢
开始课程:P19 4-4.可变长数组类的实现
课程链接:程序设计与算法(三)C++面向对象程序设计 北京大学 郭炜
课程PPT:github提供的对应课程PPT

本节课内容相对较难理解,只做两章。

1、可变长数组类的实现

此部分内容不好🦟解释:请听老师讲解,最好自己把代码敲一遍。
P19 4-4.可变长数组类的实现

// 17.cpp
# include<iostream>
using namespace std;
class CArray
{
    int size;   // 数组元素的个数
    int *ptr;   // 指向动态分配的数组
    public:
        CArray(int s=0);  // s代表数组元素的个数,构造函数
        CArray(CArray & a);
        ~CArray();
        void push_back(int v);  // 用于在数组尾部添加一个元素v
        CArray & operator = (const CArray & a);  // 用于数组对象间的赋值,深拷贝
        int length() {return size;}  // 返回数组元素个数
        // int & CArray::operator[](int i)  // 返回值为int 不行!不支持a[i] = 4
        int & operator[](int i)  // 返回值为int 不行!不支持a[i] = 4,所以返回值定义为引用
        {
            // 用以支持根据下表访问数组元素,
            // 如n=a[i]和a[i]=4;这样的语句
            return ptr[i];
        }
    //非引用的函数返回值不可以作为左值使用
};

// 构造函数
CArray::CArray(int s):size(s)
{
    if(s == 0)
        ptr = NULL;
    else    
        ptr = new int[s];  // 动态分配一个内存空间
}

// 复制构造函数(防止数组地址冲突)
CArray::CArray(CArray & a)
{
    if(!a.ptr)
    {
        ptr = NULL;
        size = 0;
        return ;
    }
    ptr = new int[a.size];
    memcpy(ptr, a.ptr, sizeof(int)*a.size);   //一共拷贝sizeof(int)*a.size字节的内容
    size = a.size;
}

// 析构函数:释放动态内存空间
CArray::~CArray()
{
    // []:属于双目运算符
    if(ptr) delete [] ptr; //释放动态分配的内存空间
    // 释放之前判断一下ptr是不是空指针
}

CArray & CArray::operator=(const CArray & a)
{
    // 赋值号的作用是使用“=”左边对象里存放的数组,大小和内容都和右边的对象一样,但是存储空间是不一样的;从而实现一种深拷贝
    if(ptr == a.ptr)  // 防止a=a这样的复制导致出错
        return * this;
    if(a.ptr == NULL)
    {
        // 如果a里面的数组是空的
        if(ptr) delete [] ptr;
        ptr = NULL;
        size = 0;
        return *this;
    }
    if(size<a.size)
    {
        // 如果原有空间够大,就不用单独分配内存空间了
        if(ptr)
        {
            delete [] ptr;
        }
        ptr = new int[a.size];
    }
    memcpy(ptr, a.ptr, sizeof(int)*a.size);
    size = a.size;
    return * this;
}   // CArray & CArray::operator=(const CArray & a)

void CArray::push_back(int v)
{
    // 在数组尾部添加一个元素
    if(ptr)
    {
        int * tmpPtr = new int[size+1]; //重新分配空间,采用临时的指针tmpPtr存储
        memcpy(tmpPtr, ptr, sizeof(int)*size);  //拷贝原数组内容
        delete[] ptr;   // 删除原本的ptr空间
        ptr = tmpPtr;  // 将ptr指向刚才零时的指针
    }
    else   // 数组本来就是空的
        ptr = new int[1];
    ptr[size++] = v; // 加入新的数组元素
}

// 要编写可变长整形数组类,使之能如下使用:
int main()
{
    CArray a;  // 开始这里的数组是空的
    for(int i=0; i < 5; ++i)
    {
        a.push_back(i);     // 要用动态分配的内存来存放数组元素,需要一个指针成员变量
    }
    CArray a2, a3;
    a2 = a;    // 要重载“=”
    for(int i=0; i<a.length(); ++i)
    {
        cout << a2[i] << " ";   // a2是一个对象名,不是数组名,对象名加中括号需要重载[]
    }
    a2 = a3;  // a2是空的
    for(int i=0; i<a2.length(); ++i)  // a2.length()返回0
    {
        cout << a2[i] << " ";
    }
    a2 = a3;
    cout << endl;
    a[3] = 100;
    CArray a4(a);  //CArray的复制构造函数
    for(int i=0; i<a4.length(); ++i)
    {
        cout << a4[i] << "";
    }
    return 0;
}

Debug:最难听懂的一行代码:“=”运算符重载
a2 = a; // 要重载“=”
a2 = a3;
下面给出了debug图片可供理解。
请添加图片描述
请添加图片描述
在这里插入图片描述

2、流插入运算符和流提取运算符的重载

课程链接:5-5流插入运算符和流提取运算符的重载
配合下方代码解释仔细听课,即可听懂。

问题1:cout << 5 << “this”;为什么能够成立?
问题2:cout是什么?

  • cout 是在 iostream 中定义的,ostream 类
    的对象。

问题3:“<<” 为什么能用在 cout上?

  • “<<” 能用在cout 上是因为,在iostream里对 “<<” 进行了重载。

2.1、对形如cout << 5 ; 单个"<<"进行重载

cout << 5 ; 即 cout.operator<<(5); // 表示对cout这个对象调用operator<<这个成员函数
cout << “this”; 即 cout.operator<<( “this” );

// 有可能按以下方式重载成 ostream类的成员函数:
void ostream::operator<<(int n). // n:可以表示左移参数5
{
	…… //输出n的代码
	return;
}

2.2、对形如cout << 5 << “this” ;连续多个"<<"进行重载

考虑返回值的问题,如果返回值是void,那么cout还能接着往下运算吗?显然不可以,如果返回值是cout,那么就可以继续调用重载

ostream & ostream::operator<<(int s). // 返回值为ostream的引用
{
…… //输出n的代码
return * this;   // this指针指向了成员函数所作用的对象,那么其就是cout。那么返回值就是cout的引用(&cout)
}
ostream & ostream::operator<<( const char * s )
{
…… //输出s的代码
return * this;
}

cout << 5 << “this”; 本质上的函数调用的形式是什么?
cout.operator<<(5).operator<<(“this”);

详解案例

例题:假定c是Complex复数类的对象,现在希望写“cout << c;”,就能以“a+bi”的形式输出c的值,写“cin>>c;”,就能从键盘接受“a+bi”形式的输入,并且使得c.real = a,c.imag = b。

#include<iostream>
#include<string>
#include<cstdlib>

using namespace std;

class Complex
{
        double real, imag;
    public:
        Complex(double r=0, double i=0):real(r),imag(i) {};
        friend ostream & operator<<(ostream & os, const Complex & c);
        friend istream & operator>>(istream & is, Complex & c); 
};

// cout是ostream的成员函数,所以我们不能去写成ostream的成员函数(已经封装好了),只能写成全局函数;
// 又因为需要访问稀有成员变量,所以要用到友元函数
// 操作数的个数等于这个函数的参数个数。可以为Complex的对象,也可以是Complex的引用(能够节省时间和空间)
// os为cout的引用,即ostream & os = cout;,所以os等于cout;那么返回值也是ostream & os;所以返回值等于cout
ostream & operator<<(ostream & os, const Complex & c)
{
    os << c.real << "+" << c.imag << "i" << "i";  // 以"a+bi"的形式输出
    return os;
}

istream & operator>>(istream & is, Complex & c)
{
    string s;
    is >> s;  // 将"a+bi"作为字符串读入,"a+bi"中间不能有空格
    int pos = s.find("+", 0);
    string sTmp = s.substr(0, pos);  // 分离出代表实部的字符串
    c.real = atof(sTmp.c_str());
    // atof库函数能将const char*指针指向的内容转换为float
    sTmp = s.substr(pos+1, s.length()-pos-2);
    // 分离出代表虚部的字符串
    c.imag = atof(sTmp.c_str());
    return is;
};

int main()
{
    Complex c;
    int n;
    cin >> c >> n;  
    cout << c << "," << n;   
    return 0;
}

//程序运行结果可以如下:
13.2+133i 87
13.2+133i, 87

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

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

相关文章

地埋电缆故障检测方法有哪些?地埋电缆故障检测费用是多少?

地埋电缆故障检测方法主要涵盖脉冲反射法、桥接法、高压闪络法和声波定位法等多种方法。选择适当的方法取决于故障类型、电缆类型和实际现场条件。至于地埋电缆故障检测费用则受到多个因素的影响&#xff0c;包括故障类型、检测方法的复杂性、检测设备的先进程度以及所处地区的…

【强化学习的数学原理-赵世钰】课程笔记(十)Actor-Critic 方法

目录 一.最简单的 actor-critic&#xff08;QAC&#xff09;&#xff1a;The simplest actor-critic (QAC) 二.Advantage actor-critic (A2C) 三.Off-policy actor-critic 方法 四. Deterministic actor critic(DPG) Actor-Critic 方法把基于 value 的方法&#xff0c;特别…

删除顺序表中所有值为X的元素(顺序表,单链表)

目录 时间复杂度为O(1)(顺序表)&#xff1a;代码实现&#xff1a; 运行结果&#xff1a; 时间复杂度为O(n)(顺序表)&#xff1a;代码实现&#xff1a; 运行结果&#xff1a; 单链表&#xff1a;时间复杂度o&#xff08;n&#xff09;:代码实现&#xff1a; 时间复杂度为O(1…

调研-转换zpl为png

文章目录 前言ZPLZPL相关转换的网站一、labelary常用功能 二、labelzoom三、https://www.htmltozpl.com/docs/demo/html-to-zpl四、 开源仓库&#xff1a;JSZPL五、 开源仓库&#xff1a;BinaryKits.Zpl六 redhawk其他相关概述Lodop 处理zpl 前言 为了解决ZPL指令转换为png&am…

软件需求开发和管理过程性指导文件

1. 目的 2. 适用范围 3. 参考文件 4. 术语和缩写 5. 需求获取的方式 5.1. 与用户交谈向用户提问题 5.1.1. 访谈重点注意事项 5.1.2. 访谈指南 5.2. 参观用户的工作流程 5.3. 向用户群体发调查问卷 5.4. 已有软件系统调研 5.5. 资料收集 5.6. 原型系统调研 5.6.1. …

Cesium中实现镜头光晕

镜头光晕 镜头光晕 (Lens Flares) 是模拟相机镜头内的折射光线的效果&#xff0c;主要作用就是让太阳光/其他光源更加真实&#xff0c;和为您的场景多增添一些气氛。 Cesium 中实现 其实 Cesium 里面也是有实现一个镜头光晕效果的&#xff0c;添加方式如下&#xff0c;只是效…

Leetcode - 周赛393

目录 一&#xff0c;3114. 替换字符可以得到的最晚时间 二&#xff0c;3115. 素数的最大距离 三&#xff0c;3116. 单面值组合的第 K 小金额 四&#xff0c; 3117. 划分数组得到最小的值之和 一&#xff0c;3114. 替换字符可以得到的最晚时间 本题是一道模拟题&#xff0c;…

泛型的初步认识(1)

前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; hellohello~&#xff0c;大家好&#x1f495;&#x1f495;&#xff0c;这里是E绵绵呀✋✋ &#xff0c;如果觉得这篇文章还不错的话还请点赞❤️❤️收藏&#x1f49e; &#x1f49e; 关注&#x1f4a5;&#x…

标准版uni-app移动端页面添加/开发操作流程

页面简介 uni-app项目中&#xff0c;一个页面就是一个符合Vue SFC规范的.vue文件或.nvue文件。 .vue页面和.nvue页面&#xff0c;均全平台支持&#xff0c;差异在于当uni-app发行到App平台时&#xff0c;.vue文件会使用webview进行渲染&#xff0c;.nvue会使用原生进行渲染。…

HCIP的学习(10)

OSPF不规则区域划分 区域划分 非骨干与骨干区域直接相连骨干区域唯一 限制规则&#xff1a; 非骨干区域之间不允许直接相互发布区域间路由信息OSPF区域水平分割&#xff1a;从非骨干区域收到的路由信息&#xff0c;ABR设备能接收到不能使用&#xff08;从某区域传出的路由&…

全新升级轻舟知识付费系统引流变现至上利器

知识付费系统&#xff1a;引流变现至上利器 本系统参考各大主流知识付费系统&#xff0c;汇总取其精华&#xff0c;自主研发&#xff0c;正版授权系统。 我们给你搭建搭建一个独立运营的知识付费平台&#xff0c;搭建好之后&#xff0c;你可以自由的运营管理。网站里面的名称…

【机器学习】分类与预测算法评价的方式介绍

一、引言 1、机器学习分类与预测算法的重要性 在数据驱动的时代&#xff0c;机器学习已经成为了处理和分析大规模数据的关键工具。分类与预测作为机器学习的两大核心任务&#xff0c;广泛应用于各个领域&#xff0c;如金融、医疗、电商等。分类算法能够对数据进行有效归类&…

web前端网络相关知识

一、OSI 7层参考模型 1.物理层&#xff08;光纤、电缆等物理介质&#xff09; 传播比特流&#xff08;bit&#xff09; 01010101的形式 2.数据链路层&#xff08;交换机&#xff0c;mac地址&#xff09; 将比特流组合成字节&#xff0c;组合成帧&#xff0c;用mac地址访问&…

bugku-web-login2

这里提示是命令执行 抓包发现有五个报文 其中login.php中有base64加密语句 $sql"SELECT username,password FROM admin WHERE username".$username.""; if (!empty($row) && $row[password]md5($password)){ } 这里得到SQL语句的组成&#xff0c;…

CRMEB PRO安装系统配置清单

统在安装完成之后&#xff0c;需要对系统进行一系列的配置&#xff0c;才能正常使用全部的功能&#xff0c;以下是官方整理的配置清单

Xinstall带你进入一键通过URL打开App的新时代

在移动互联网时代&#xff0c;App已经成为我们日常生活中不可或缺的一部分。然而&#xff0c;在使用App的过程中&#xff0c;我们常常会遇到一些烦恼。比如&#xff0c;当我们通过一个网页链接想要打开对应的App时&#xff0c;往往需要先复制链接&#xff0c;然后在App中粘贴&a…

2024的新宠儿——Mamba(1):SSM

引言 自 2017 年被提出以来,Transformer 已经成为 AI 大模型的主流架构,但随着模型规模的扩展和需要处理的序列不断变长,Transformer 的局限性也逐渐凸显。一个很明显的缺陷是:Transformer 模型中自注意力机制的计算量会随着上下文长度的增加呈平方级增长,比如上下文增加 …

多模态之ALBEF—先对齐后融合,利用动量蒸馏学习视觉语言模型表征,学习细节理解与论文详细阅读:Align before Fuse

Align before Fuse: Vision and Language Representation Learning with Momentum Distillation &#xff08;ALBEF&#xff09;在融合之前对齐&#xff1a;利用动量蒸馏进行视觉与语言表示学习 Paper: arxiv.org/pdf/2107.07651.pdf Github: https://github.com/salesforce/…

用云手机运营TikTok有什么好处?

在数字化浪潮的推动下&#xff0c;社交媒体平台正重塑商业推广与品牌建设的面貌。TikTok&#xff0c;这款全球热门的短视频应用&#xff0c;已经吸引了亿万用户的瞩目。对于出海电商和品牌推广而言&#xff0c;借助云手机运营TikTok&#xff0c;能够解锁更多潜在可能&#xff0…

Linux:进程调度

Linux&#xff1a;进程调度 进程优先级查看优先级调整优先级 Linux 2.6 内核进程调度队列 进程优先级 查看优先级 在Linux中&#xff0c;进程是有优先级的&#xff0c;我们可以通过指令ps -la来查看&#xff1a; 其中PRI表示priority优先级&#xff0c;在Linux中&#xff0c;…