2023/9/11 -- C++/QT

news2024/11/20 8:44:22

作业

仿照string类,完成myString 类

02mystring.h:

#ifndef __02MYSTRING_H__
#define __02MYSTRING_H__

#include <iostream>
#include <cstring>

using namespace std;

class myString{
private:
    char *str;
    int size;
public:
    //无参构造
    myString();
    //有参构造
    myString(const char *s);
    //拷贝构造
    myString(const myString &other);
    //析构函数
    ~myString();
    //拷贝赋值函数
    myString & operator=(const myString &other);
    //判空
    bool empty()const;
    //size
    size_t string_size()const;
    //c_str
    const char *c_str(const myString &s)const;
    //at
    char &at(int pos)const;
    //+运算符
    const myString operator+(const myString &s)const;
    //+=运算符
    myString &operator+=(const myString &s);
    //>运算符
    bool operator>(const myString &s)const;
    //[]运算符
    char operator[](int index)const;
};

#endif // 02MYSTRING_H

 02mystring.cpp:

#include <02mystring.h>
//无参构造
myString::myString():size(10){
    str = new char[size];
    strcpy(str,"");
}
//有参构造
myString::myString(const char *s){
    size = strlen(s);
    str = new char[size+1];
    strcpy(str,s);
}
//拷贝构造
myString::myString(const myString &other):size(other.size){
    str = new char[size+1];
    strcpy(str,other.str);
}
//析构函数
myString::~myString(){
    delete []str;
    str = nullptr;
}
//拷贝赋值函数
myString & myString::operator=(const myString &other){
    size = other.size;
    strcpy(str,other.str);
    return *this;
}
//判空
bool myString::empty()const{
    return size == 0;
}
//size
size_t myString::string_size()const{
    return size;
}
//c_str
const char *myString::c_str(const myString &s)const{
    char *c_string = new char[s.size+1];
    strcpy(c_string,s.str);
    return c_string;
}
//at
char &myString::at(int pos)const{
    if(pos < 0 || pos >= size){
        cout<<"pos出错啦!"<<endl;
        return *str;             //不知道返回值些什么...嘻嘻,就返回第一个位置...
    }
    return *(str+pos);
}
//+运算符
const myString myString::operator+(const myString &s)const{
    myString S;
    S.size = size + s.size;
    strcpy(S.str,str);
    strcat(S.str,s.str);
    return S;
}
//+=运算符
myString &myString::operator+=(const myString &s){
    size += s.size;
    strcat(str,s.str);
    return *this;
}
//>运算符
bool myString::operator>(const myString &s)const{
    return strcmp(str,s.str) > 0;
}
//[]运算符
char myString::operator[](int index)const{
    return *(str+index);
}

main.cpp:

#include <02mystring.h>

int main()
{
    myString s1("hello");
    myString s2("world");
    cout<<"s1.size = "<<s1.string_size()<<endl;
    cout<<"c_str(s2) = "<<s2.c_str(s2)<<endl;
    myString s3 = s1 + s2;
    cout<<"s3.at(5) = "<<s3.at(5)<<endl;
    myString s4("nihao");
    s4 += s2;
    if(s4 > s3){
        cout<<"s4 > s3"<<endl;
    }else {
        cout<<"s4 <= s3"<<endl;
    }
    cout<<"s4[4] = "<<s4[4]<<endl;
    return 0;
}

 效果图:

一、友元(friend)

1.1 友元函数

1> 普通的类的非成员函数,是无权访问类中的受保护成员以及私有成员的,但是,将一个函数设置成友元函数,那么该函数可以访问该类中的所有权限下的成员,

2> 友元函数分为全局函数作为友元函数和其他类的成员函数作为友元函数

3> 全局函数作为友元函数格式:在类内进行全局函数的声明:friend 函数头;

4> 其他类的成员函数作为友元函数,声明格式:friend 其他类::函数名(形参列表);

1.2 友元类

将一个类声明成友元类,那么就运行这个类中的所有成员函数来访问自己类中的私有成员了

#include <iostream>

using namespace std;
class Stu;             //对类的前置声明

void fun(Stu &s);            //将函数进行前置声明

class Teacher
{
private:
    string name;
    string subject;          //科目

public:
    Teacher() {}
    Teacher(string n, string s):name(n), subject(s) {}

    void display(Stu &s);             //类内声明,类外定义

};

class Stu
{
private:
    string name;
    int age;
    double score;

public:
    Stu() {}
    Stu(string n, int a, double s):name(n),age(a),score(s) {}

    //类中的成员函数,可以直接使用所有权限下的成员
    void show()
    {
        cout<<"name = "<<name<<"  age = "<<age<<"  score = "<<score<<endl;
    }

    //将全局函数声明成友元函数,那么该全局函数可以访问该类中的所有权限下的成员
    friend void fun(Stu &s);

    //将老师类中的成员函数设置成友元函数
    //friend void Teacher::display(Stu &s);

    //将整个老师类都声明成友元类
    friend class Teacher;
};

//定义一个全局函数
void fun(Stu &s)
{
    cout<<"name = "<<s.name<<"  age = "<<s.age<<"  score = "<<s.score<<endl;
}

//将老师类中的成员函数类外定义
void Teacher::display(Stu &s)
{
    cout<<"my_name = "<<name<<endl;
    cout<<"my_subject = "<<subject<<endl;

    cout<<"stu_name = "<<s.name<<endl;
}

int main()
{
    Stu s("zhangpp", 18, 90);
    fun(s);

    Teacher t("zhansan", "C++");
    t.display(s);

    return 0;
}

1.3 友元的总结

  1. 友元是单向的,A将B设置成友元,则A允许B访问自己的成员,而B不一定允许A访问其成员
  2. 友元不具有传递性:A是B的朋友,B是C的朋友,那么A不一定是C的朋友
  3. 友元不具有继承性:父类的朋友不一定是子类的朋友
  4. 友元破坏了类的封装性,使得访问权限形同虚设,所以不在万不得已的情况下,尽可能不使用友元
  5. 必须使用友元的情况:插入和提取运算符重载时,需要使用全局函数作为友元函数

二、常成员(const)

2.1 常成员函数

1> 在定义成员函数后,加关键字const,那么该函数就是常成员函数

2> 在常成员函数中,不能修改成员变量的值,保护成员变量不被修改,但是可以使用成员变量

3> 常成员函数和同名的非常成员函数,即使参数种类和个数等同,也构成重载关系,原因是this指针的类型不同

                非常成员函数中this: 类名 * const this;

                常成员函数中this:const 类名 * const this;

4> 非常对象,调用成员函数时,优先调用非常成员函数,如果没有非常成员函数,那么就调用同名的常成员函数

2.2 常对象

1> 定义对象时,加关键字const: const 类名 对象名;

2> 常对象只能调用常成员函数,不能调用非常成员函数

2.3 mutable关键字

该关键字可以修饰类中的成员变量,表示该变量可以在成员函数中被修改

#include <iostream>

using namespace std;
class Stu
{
private:
    string name;
    mutable int age;            //由mutable修饰的成员变量,可以在常成员函数中被修改
    double score;

public:
    Stu() {}
    Stu(string n, int a, double s):name(n),age(a),score(s) {}

    //类中的成员函数,可以直接使用所有权限下的成员
    void show()const            //this原型:const 类名  * const this;
    {
        //this->score = 100;              //更改成员变量的值
        this->age = 16;            //由于该成员变量由mutable修饰,取消了其常属性
        cout<<"name = "<<name<<"  age = "<<age<<"  score = "<<this->score<<endl;
    }

    //定义同名的非常成员函数
    void show()                   //this原型:类名  * const this;
    {
        this->score = 100;              //更改成员变量的值
        cout<<"name = "<<name<<"  age = "<<age<<"  score = "<<score<<endl;
    }
};

int main()
{
    Stu s1("zhangs", 18, 90);
    //s1.show();                      //100

    const Stu s2("lisi", 20, 50);        //该对象为常对象
    //s2.show();

    //定义常引用,目标为非常对象
    const Stu &ref = s1;

    ref.show();            // 常引用也有常属性,调用成员函数时,只能调用常成员函数,不能调用非常成员函数
    s1.show();            //调用非常成员函数

    return 0;
}

三、运算符重载(operator)

3.1 定义

所谓运算符重载,本质上也是静态多态的一种,能够实现“一符多用”,使用运算符重载,能够完成运算符作用于类对象之间,使得代码更加简洁、可读性更强。

3.2 重载的方法

所有运算符重载,都拥有一个统一的名称:operator# (#表示运算符号)

参数:根据运算符本身特点决定,如果是单目运算符,最多拥有一个参数,如果是双目运算符,最多拥有两个参数

返回值:由用户自己决定

3.3 调用原则及调用时机

1> 调用时机:使用该运算符时,系统自动调用,无需手动调用

2> 调用原则:左调右参 (运算符的左侧是函数调用者,右侧是该函数的参数) 例如:a = b; //a.operator=(b)

3.4 重载版本

每个运算符重载,都可以实现两个版本的重载函数,分别是成员函数版和全局函数版

成员函数版比全局函数版本少一个参数,因为类对象本身就是一个参数

全局函数版和成员函数版只能实现一个,否则会造成调用时的混乱情况

3.5 算术类运算符重载

1> 种类:+、-、*、/、%

2> 表达式格式:L # R //L表示左操作数 #表示运算符 R表示右操作数

3> 左操作数:既可以是左值也可以是右值,运算过程中不会被修改

4> 右操作数:既可以是左值也可以是右值,运算过程中不会被修改

5> 结果:结果是一个同类的右值,不能被改变

6> 定义格式:

全局函数版:const 类名 operator# (const 类名 &L, const 类名 &R)

成员函数版:const 类名 operator# ( const 类名 &R)const

3.6 关系类运算符重载

1> 种类:>、=、

2> 表达式格式:L # R //L表示左操作数 #表示运算符 R表示右操作数

3> 左操作数:既可以是左值也可以是右值,运算过程中不会被修改

4> 右操作数:既可以是左值也可以是右值,运算过程中不会被修改

5> 结果:bool类型,表示真假

6> 定义格式:

全局函数版:bool operator# (const 类名 &L, const 类名 &R)

成员函数版:bool operator# ( const 类名 &R)const

3.7 赋值类运算符重载

1> 种类:=、+=、-=、*=、/=、%=

2> 表达式格式:L # R //L表示左操作数 #表示运算符 R表示右操作数

3> 左操作数:只能是左值

4> 右操作数:既可以是左值也可以是右值,运算过程中不会被修改

5> 结果:自身的引用

6> 定义格式:

全局函数版:类名 &operator# (类名 &L, const 类名 &R)

成员函数版:类名 & operator# ( const 类名 &R)

3.8 单目运算符重载

1> 种类:!、~、*、&、-

2> 表达式格式: # O                 // #表示运算符 O表示操作数

3> 操作数:既可以是左值也可以是右值,运算过程中不能更改

4> 结果:同类的右值

5> 定义格式:

全局函数版:类名 operator# (const 类名 &O)

成员函数版:类名 operator# ( )const

#include <iostream>


using namespace std;

//定义一个复数类 5 + 3i
class Complex
{
private:
    int real;         //实部
    int vir;          //虚部
public:
    Complex() {}
    Complex(int r, int v):real(r), vir(v) {}         //有参构造
    //定义展示函数
    void show()
    {
        if(vir>=0)
        {
            cout<<real<<" + "<<vir<<"i"<<endl;
        }else
        {
            cout<<real<<vir<<"i"<<endl;
        }
    }

    //全局函数版实现加运算符重载
    friend const Complex operator+ (const Complex &L, const Complex &R);

    //成员函数版实现运算符重载
    const  Complex  operator- ( const Complex  &R)const
    {
        Complex c;
        c.real = this->real - R.real;
        c.vir = this->vir - R.vir;
        return c;
    }

    //成员函数版实现关系运算符的重载:实部>实部  && 虚部>虚部
    bool operator>(const Complex &R)const
    {
        return this->real>R.real&&this->vir>R.vir;
    }

    //重载中括号运算符
    int & operator[](int index)
    {
        if(index == 0)
        {
            return real;          //返回实部
        }else if(index == 1)
        {
            return vir;           //返回虚部
        }
    }

    //重载+=运算符:实部+=实部   虚部+=虚部
    Complex & operator+=(const Complex &R)
    {
        this->real += R.real;
        this->vir += R.vir;
        return *this;                //返回自身的引用
    }

    //重载负号运算符: 实部= -实部, 虚部 = -虚部
    Complex operator-()
    {
        Complex c;
        c.real = -this->real;
        c.vir = -this->vir;
        return c;
    }
};

//全局函数版实现加号运算符重载:实部+实部  虚部+虚部
const Complex operator+ (const Complex &L, const Complex &R)
{
    //定义一个临时空间
    Complex c;


    c.real = L.real + R.real;
    c.vir = L.vir + R.vir;


    return c;
}

int main()
{
    Complex c1(5,3);
    c1.show();                    //5+3i

    Complex c2(2,-1);
    c2.show();                      //2-1i

    Complex c3 = c1-c2;             //调用加法运算符重载函数  c1.operator-(c2)

    c3.show();                      //3+4i

    if(c3 > c2)              //调用关系运算符重载函数
    {
        cout<<"yes"<<endl;
    }else
    {
        cout<<"no"<<endl;
    }

    c3[0] = 5;               //将实部进行修改成5,调用中括号运算符重载
    c3.show();                  //5+4i

    c3 += c2;            //调用+=运算符重载函数
    c3.show();             //7+3i

    Complex c4 = -c3;      //调用-号运算符重载
    c4.show();              //-7 - 3i
    c3.show();            //7+3i

    return 0;
}

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

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

相关文章

C++算法 —— 动态规划(5) 子序列

文章目录 1、动规思路简介2、最长递增子序列3、摆动序列4、最长递增子序列的个数5、最长数对链6、最长定差子序列7、最长斐波那契子序列的长度8、最长等差数列9、等差数列划分 II 每一种算法都最好看完第一篇再去找要看的博客&#xff0c;因为这样会帮你梳理好思路&#xff0c;…

Python 图形化界面基础篇:添加标签( Label )到 Tkinter 窗口

Python 图形化界面基础篇&#xff1a;添加标签&#xff08; Label &#xff09;到 Tkinter 窗口 引言什么是 Tkinter 标签&#xff08; Label &#xff09;&#xff1f;步骤1&#xff1a;导入 Tkinter 模块步骤2&#xff1a;创建 Tkinter 窗口步骤3&#xff1a;创建标签&#x…

kafka管理工具之kafka-ui的环境搭建笔记

由于项目需要kafka支持认证功能&#xff0c;就把kafka升级到3.2.0了。之前一直使用的kafka tools(现在叫Offset Explorer&#xff0c;个人使用免费&#xff0c;商用付费)&#xff0c;开了认证之后就不好用了&#xff0c;卡的很&#xff0c;一点也不丝滑了&#xff0c;于是只好重…

pytorch代码实现之Partial Convolution (PConv卷积)

Partial Convolution (PConv卷积) Partial Convolution (PConv卷积)&#xff0c;有助于提升模型对小目标检测的性能。目前许多研究都集中在减少浮点运算&#xff08;FLOPs&#xff09;的数量上。然而FLOPs的这种减少不一定会带来延迟的类似程度的减少。这主要源于每秒低浮点运…

浅析建筑电气火灾问题和预防方案

安科瑞 华楠 摘要&#xff1a;近几年来随着技术化和信息化的不断发展&#xff0c;电器在建筑中的应用也是越来越广泛&#xff0c;电气也成为人们生活当中的一部分。现如今建筑物设计中都要增加电气线路的设计&#xff0c;几年电气引起的火灾也不在少数。建筑电气在运行的过程中…

OpenCV(三十七):拟合直线、三角形和圆形

1.点集拟合的含义 点集拟合是一种通过拟合函数或曲线来近似描述给定离散数据点的技术,在点集拟合中&#xff0c;可以使用不同的函数或曲线拟合方法来拟合直线、三角形和圆形。 直线拟合&#xff1a;对于给定的二维数据点集合&#xff0c;可以使用最小二乘法来拟合一条直线。 …

springboot之三:原理分析之自动配置condition

导入&#xff1a; SpringBoot是如何知道要创建哪个Bean的&#xff1f;比如Spring Boot是如何知道要创建RedisTemplate的&#xff1f; Condition&#xff1a; Condition是在Spring4.0增加的条件判断功能&#xff0c;通过这个可以实现选择性的创建Bean操作。 自定义条件&…

C++之string::npos应用实例(一百九十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

使用IDEA创建Vue3通过Vite实现工程化

1、创建Vite项目的分步说明 IntelliJ IDEA与Vite构建工具集成&#xff0c;改善了前端开发体验。Vite 由一个开发服务器和一个构建命令组成。构建服务器通过本机 ES 模块提供源文件。生成命令将代码与汇总捆绑在一起&#xff0c;汇总预配置为输出高度优化的静态资产以供生产。In…

AI绘画:Midjourney超详细教程Al表情包超简单制作,内附关键词和变现方式

大家好&#xff0c;本篇文章主要介绍AI绘画完成表情包的制作和变现方式分享。 你还不会AI表情包制作吗&#xff1f;下面我们详细的拆解制作过程。跟着这个教程做出一套属于自己的表情包。 核心工具Midjourney PS&#xff0c;你就可以得到一套自己的专属表情包啦~ 整体制作…

Go 基础15-在init()函数中检查包级变量的初始状态

从程序逻辑结构角度来看&#xff0c;包&#xff08;package&#xff09;是Go程序逻辑封装的基本单元&#xff0c;每个包都可以理解为一个“自治”的、封装良好的、对外部暴露有限接口的基本单元。一个Go程序就是由一组包组成的。 在Go包这一基本单元中分布着常量、包级变量、函…

胡焕庸线,我国东西地级市分布密度分界线

背景 黑河—腾冲线&#xff0c;又名胡焕庸线&#xff0c;是我国人口密度分布的东西近似分界线。今天把地级市坐标分布密度做成热力图&#xff0c;并与胡焕庸线一起展示时&#xff0c;惊奇的发现&#xff0c;胡焕庸线貌似也是我车东西地级市分布密度的分界线。 生成folium地图…

【17 > 分布式接口幂等性】2. Update的幂等性原理解析

一、 根据 唯一业务号去更新 数据的情况 1.1 原理 1.2 操作 1.3 实战 Stage 1&#xff1a;表添加 version 字段 Stage 2&#xff1a;前端 > 版本号放入隐藏域 Stage 3&#xff1a;后台 > 使用版本号作为更新条件 二、更新操作没有唯一业务号&#xff0c;可使用Tok…

FL Studio Producer Edition 21.0.3.3713中文完整破解版功能特点及安装激活教程

FL Studio Producer Edition 21.0.3.3713中文完整破解版是一款由Image Line公司研发几近完美的虚拟音乐工作站,同时也是知名的音乐制作软件。它让你的计算机就像是全功能的录音室&#xff0c;漂亮的大混音盘&#xff0c;先进的创作工具&#xff0c;让你的音乐突破想象力的限制。…

4.2 Ioc容器加载过程-Bean的生命周期深度剖析

Bean生命周期详解 第一步拿到父类BeanFactory子类 第二步&#xff0c;读取配置类 AnnotatedBeanDefinitionReader 用来读取配置类之外和还做了 第一个是解析类的处理器&#xff0c;没有的话我们的配置类就无法解析 总结this()无参构造函数里面实现了【三大步】 实例…

九安监控初始化后恢复案例

九安监控是国内一个十六线小安防品牌&#xff0c;目前CHS零壹视频恢复程序监控版、专业版、高级版是支持这个安防品牌的&#xff0c;不过下边这个案例比较特殊&#xff0c;具体情况如下。 故障存储:希捷4T监控专用硬盘 故障现象: 客户描述是使用了初始化操作&#xff0c;正常…

Linux中防火墙的简单使用方法

目录 前言 一、概念 1、防火墙的分类&#xff1a; 2、防火墙性能 3、硬件防火墙的品牌、软件防火墙的品牌 4、硬件防火墙与软件防火墙比较 二、linux中的防火墙 1、iptables 2.netfilter/iptables功能 3、四表 iptables中表的优先级 4、五链 三、iptables 1、ipt…

YOLO DNF辅助教程完结

课程完结&#xff01;撒花、撒花、撒花 课程完结&#xff01;撒花、撒花、撒花 课程完结&#xff01;撒花、撒花、撒花 ​呕心沥血三个月&#xff0c;《利用人工智能做DNF游戏辅助》系列实战课程已完结&#xff0c;技术路线贯穿串口通信、目标检测、opencv特征匹配等前沿技术…

计算机组装与维护实训室解决方案

一、产业背景 随着信息技术的不断发展&#xff0c;信息化已经深入到社会中各个层面&#xff0c;它能有效地帮助各个行业提高运营及管理效率&#xff0c;进而帮助企业成长。同时&#xff0c;作为企业信息化建设的基础部分&#xff0c;计算机已经融入了我们的生活&#xff0c;并逐…