当前位置: 首页 > article >正文

c++自定义String

mystring.c

#include "mystring.h"
#define SIZE 8
#include"mystring.h"
//计算所需最小满足len的容量 每次都是8的倍数
int max_size(int len,int maxsize){

    while(len>maxsize){
        maxsize*=2;
    }
    return maxsize;
}
//构造函数
mystring::mystring(){
    //初始化
    size=0;
    maxsize=SIZE;
    str=new char[size];
    cout<<"无参构造"<<endl;
}
//有参构造
mystring::mystring(const char * str1){
    //初始化
     size=strlen(str1);
    maxsize=max_size(size+1,SIZE);//计算出最小满足len的容量 需要考虑'\0'
    str=new char[maxsize];
    //拷贝
    memcpy(str,str1,size+1);//需要考虑'\0'
    cout<<"mystring::有参"<<endl;

}
mystring::mystring(int n,char ch){
    maxsize=max_size(n+1,SIZE);//\0
    size=n;
    str=new char[maxsize];
    int i=0;
    for(i=0;i<size;i++){
        str[i]=ch;
    }
    str[i]='\0';

}
//析构函数
mystring::~mystring(){
    delete []str;
    cout<<"析构"<<endl;
}
//拷贝构造函数
mystring ::mystring(const mystring &other){
    //初始化
    if(other.str==NULL){return ;}
    size=other.size;
    maxsize=other.maxsize;
    str=new char[maxsize];
    //拷贝
    memcpy(str,other.str,maxsize);
    cout<<"拷贝构造函数"<<endl;
}


//拷贝赋值函数
mystring & mystring::operator=(const mystring &other){
    size=other.size;
    maxsize=other.maxsize;
    delete []str;
    str=new char[maxsize];
    memcpy(str,other.str,maxsize);
    cout<<"拷贝赋值函数"<<endl;
    return *this;
}
mystring & mystring::operator=(const char * str1){
    //初始化
     size=strlen(str1);
     maxsize=SIZE;
    maxsize=max_size(size+1,maxsize);
    str=new char[maxsize];//需要考虑'\0'
    //拷贝
    memcpy(str,str1,size+1);
    cout<<"拷贝赋值函数"<<endl;
    return *this;
}
//判空函数
bool mystring::isempty(){
    if(size==0){
        return true;
    }
    return false;
}
//size函数
int mystring::mysize(){
    if(str==NULL) return -1;
    return size;
}
//c_str函数
char * mystring::c_str(){
    return str;
}
//at函数
char & mystring::at(int n){
    return str[n];
}
//二倍扩容
void mystring::expent(){
    char * temp=new char[maxsize*2];
    if(temp==NULL){
        perror("expent");
        return ;
    }
    memcpy(temp,str,maxsize);
    delete []str;
    str=temp;
    maxsize*=2;

}
//实现+=运算符重载            s1 += s2
mystring & mystring::operator+=(const mystring &other){
    //扩容
    while(1){
        //如果可以容纳就跳出循环
        if(maxsize>=other.size+size+1)//注意\0
        {
          break;
        }
        //扩容
        expent();
    }
    //追加
    strcat(str,other.str);

    return *this;
}

mystring & mystring::operator+=(const char* &str1){
    //计算大小
    int len=strlen(str1);
    //扩容
    while(1){
        //如果可以容纳就跳出循环
        if(maxsize>=len+size+1)//注意\0
        {
          break;
        }
        //扩容
        expent();
    }
    //追加
    strcat(str,str1);

    return *this;
}
//取地址运算符重载
mystring * mystring::operator&(){
    cout<<"取地址运算重载"<<endl;
return this;
}
char & mystring::operator [](int n){
    return str[n];
}
mystring mystring::operator +(mystring other){

    while(1){
        //如果可以容纳就跳出循环
        if(maxsize>=other.size+size+1)//注意\0
        {
          break;
        }
        //扩容
        expent();
    }
    //追加
    strcat(str,other.str);

    return *this;
}
//关系函数
bool  mystring::operator ==(mystring &n){
    return strcmp(str,n.c_str())==0;
}
bool  mystring::operator !=(mystring &n){
     return strcmp(str,n.c_str())!=0;
}
bool  mystring::operator <=(mystring &n){
         return strcmp(str,n.c_str())<0||strcmp(str,n.c_str())==0;;
}
bool  mystring::operator >=(mystring &n){
    return strcmp(str,n.c_str())>0||strcmp(str,n.c_str())==0;;
}
bool  mystring::operator >(mystring &n){
      return strcmp(str,n.c_str())>0;
}
bool  mystring::operator <(mystring &n){
      return strcmp(str,n.c_str())<0;
}
//输入输出
 ostream & operator <<(ostream &cout,mystring & other){
     cout<<other.c_str();
     return cout;
 }
 istream & operator >>(istream &cin,mystring & other){
    //定义缓冲区
     char buf[1024];
     cin>>buf;
     //获取长度
     other.size=strlen(buf);
     //比较是否大于最大长度,大于就修改最大长度并且申请内存
     if(other.size+1>other.maxsize){
         //计算最小所需内存空间
         other.maxsize=max_size(other.size+1,other.maxsize);
         char * temp=new char[other.maxsize];
         delete [] other.str;
         other.str=temp;
     }
     //拷贝
     strcpy(other.str,buf);

     return cin;
 }

mystring.h

#ifndef MYSTRING_H
#define MYSTRING_H
#include<iostream>
#include<cstring>
using namespace std;

class mystring
{
    char *str;
    int size;

public:
        int maxsize;//记录容量
    mystring();
    mystring(const char *);
    mystring(int n,char ch);
    ~mystring();
    //*******//
    //拷贝构造函数
    mystring(const mystring &other);
    //拷贝赋值函数
    mystring & operator=(const mystring &other);
    mystring & operator=(const char * str1);
    //判空函数
    bool isempty();
    //size函数
    int mysize();
    //c_str函数
    char * c_str();
    //at函数
    char & at(int n);
    //二倍扩容
    void expent();
    //实现+=运算符重载            s1 += s2
    mystring & operator+=(const mystring &other);
    mystring & operator+=(const char* &);
    //取地址运算符重载
    mystring * operator&();
    //访问指定字符
    char & operator [](int n);

    mystring  operator +(mystring );
    //关系函数
    bool  operator ==(mystring &n);
    bool  operator !=(mystring &n);
    bool  operator <=(mystring &n);
    bool  operator >=(mystring &n);
    bool  operator >(mystring &n);
    bool  operator <(mystring &n);
    //输入输出
    friend ostream & operator <<(ostream &cout,mystring & other);
    friend istream & operator >>(istream &cin,mystring & other);

};
//输入输出
ostream & operator <<(ostream &cout,mystring & other);
istream & operator >>(istream &cin,mystring & other);

#endif // MYSTRING_H

学习笔记

运算符重载

算数类运算符重载

  • 1> 种类:+ 、-、*、/、%、&、| 。。。。。
  • 2> 使用格式: L # R //L表示左操作数,#表示运算符号 R表示右操作数
  • 3> 左操作数L : 可以是左值也可以是右值,运算后不会被更改
  • 4> 右操作数:可以是左值也可以是右值,运算后不会被更改
  • 5> 运算结果:是一个右值,临时空间,结果不能被改变
  • 6> 函数定义格式:
    • 全局函数版:const 类名 operator#(const 类名 &L, const 类名 &R )
    • 成员函数版:const 类名 operator#(const 类名 &other) const

关系运算符重载

  • 1> 种类:> 、<、==、!=、>=、<=
  • 2> 使用格式: L # R //L表示左操作数,#表示运算符号 R表示右操作数
  • 3> 左操作数L : 可以是左值也可以是右值,运算后不会被更改
  • 4> 右操作数:可以是左值也可以是右值,运算后不会被更改
  • 5> 运算结果:是一个bool类型的右值
  • 6> 函数定义格式:
    • 全局函数版:bool operator#(const 类名 &L, const 类名 &R )
    • 成员函数版:bool operator#(const 类名 &other) const

单目运算符

单目运算符重载

  • 1> 种类:!(逻辑非)、~(按位取反)、 - (负号)、&(取地址运算符)、*(取值运算符)
  • 2> 使用格式:#O //#表示运算符号 O表示操作数
  • 3> 操作数O : 可以是左值也可以是右值,运算后不会被更改
  • 4> 运算结果:同类的右值 (*取值运算除外)
  • 6> 函数定义格式:
    • 全局函数版:类名 operator#(const 类名 &O )
    • 成员函数版:类名 operator#() const

自增自减运算符

后置自增
  1. 使用格式 :O++
  2. 操作数0 只能是左值
  3. 运算结果是自增的右值
  4. 函数定义格式
    • 全局函数版:类名 operator # (const 类名 &o,int)
    • 成员函数: 类名 operator #(int ) const
前置自增
  1. 使用格式:++O //O表示操作数
  2. 操作数O : 只能是左值
  3. 运算结果:自身的引用
  4. 函数定义格式:
    - 全局函数版:类名 operator#(const 类名 &O )
    - 成员函数版:类名 operator#() const

插入和提取运算符重载(<< 和 >>)

介绍

cin和cout对象的来源:cin是istream的一个类对象 cout是ostream的一个类对象

iostream
istream
ostream
iostream.h
  • 2> 当使用<<或者>>进行运算时:cout << 类对象
    本质上:cout.operator<<(类对象)
  • 3> 如果要重载插入和提取运算符,可以使用成员函数版和全局函数版
    但是,如果想要完成成员函数版,需要在istream或者ostream类中进行修改类体,难度很大,也没有必要
    • 此时,就只能使用全局函数版。使用全局函数版,那么就需要在运算符两次的操作数所在的类对象内将全局函数进行声明成友元
    • 由于友元的作用是为了访问操作数的私有成员,在运算过程中,不需要访问cin或cout的私有成员,所以,无需在istream或者ostream类中,将全局函数设置成友元,只需在自定义类中将全局函数设置成友元即可
  • 4> 使用格式:cin>>对象名 或者 cout<<对象名
  • 5> 左操作数:istream或者ostream类对象
  • 6> 右操作数:自定义的类对象
  • 7> 结果:左操作数自身引用
  • 格式

ostream & operator << (ostream & cout,类名 & R)
stream & operator >> (istream & cin,类名 &R)

静态成员函数

静态成员变量

  • 1> 定义格式:在函数头前加关键字 static ,那么该函数就是静态成员函数
  • 2> 静态成员函数,不依赖于某个类对象而独立存在,说明无需实例化对象,就可以调用该函数
  • 3> 静态成员函数调用方式也有两种:
    1. 通过类对象进行调用
    2. 通过类名直接调用
  • 4> 静态成员函数相当于将全局函数封装在类体内,通过类名直接使用
  • 5> 静态成员变量,没有 this 指针,在静态成员函数中,只能使用静态成员变量,不能使用非静态成员变量
  • 6> 类中静态成员函数与同名的非静态成员函数不构成重载关系

匿名对象

  • 1> 匿名对象就是没有名字的对象,直接调用类的构造函数完成定义
  • 2> 匿名对象的生命周期很短,仅仅只是在所在语句行内
  • 3> 匿名对象的使用场景:
    1. 使用匿名对象给一个新对象进行初始化
    2. 使用匿名对象当做函数的形参
    3. 使用匿名对象给对象数组进行初始化
  • 4> 匿名对象也可以像有名对象一样调用相关成员

一、继承(inherit)

面向对象的三大特征:封装、继承、多态
所谓继承:就是基于已有的类,去定义一个新类的过程就叫做继承

1.1 继承的引入

  • 1> 程序员在定义某些类的时候,很多个类,可能有很多相似的地方,我们可以将这些相似点提取出来,定义为基类,其他所有子类继承自该类,即使在子类中,没有定义某些成员,该子类中也已经存在。
  • 2> 继承的好处:
    • 1、能够大大提高代码的复用性
    • 2、继承是多态的必要条件,没有继承就没有多态
    • 3> 一个类A继承自类B: 我们称 类B为父类、基类

    类A为子类、派生类

1.2 继承格式

  • 1> 格式
class  子类名 : 继承方式1  父类名1, 继承方式2 父类名2,。。。,继承方式n 父类名n
{
    子类自己的成员
};
  • 2> 一个子类可以由一个或多个父类共同派生出来,子类会继承所有父类中所有的成员
  • 3> 继承方式:类的继承方式有三种,分别是public、protected、private
  • 4> 默认的继承方式为private,但是常用的继承方式是public
父类的 public 成员父类的 protected 成员父类的 private 成员
public继承子类中为 public子类中为 protected子类中无法访问
protected继承子类中为 protected子类中为 protected子类中无法访问
private继承子类中为 private子类中为 private子类中无法访问

在上述表格中,清晰地展示了在不同继承方式下,父类中不同访问修饰符的成员在子类中的访问属性变化情况 。在C++中,private成员对于子类来说是完全不可见的,不能通过任何方式在子类中直接访问。而publicprotected成员在不同继承方式下,在子类中的访问权限会发生相应的改变。

1.3 子类对父类继承步骤

1> 全盘吸收父类的所有成员,包括私有成员
2> 改造父类继承下来的成员,通过关键字 using
3> 拓展子类自己的成员


http://www.kler.cn/a/503047.html

相关文章:

  • 分布式缓存redis
  • JAVA:利用 RabbitMQ 死信队列实现支付超时场景的技术指南
  • GO语言实现KMP算法
  • 【HarmonyOS之旅】基于ArkTS开发(二) -> UI开发二
  • R语言的语法糖
  • 图解Git——分支的新建与合并《Pro Git》
  • 【Pytorch实用教程】PyTorch 中如何输出模型参数:全面指南
  • 战略与规划方法——深入解析波士顿矩阵(BCG Matrix):分析产品组合的关键工具
  • Python----Python高级(函数基础,形参和实参,参数传递,全局变量和局部变量,匿名函数,递归函数,eval()函数,LEGB规则)
  • python中bug修复案例-----数据类型不匹配错误导致的bug修复
  • 如何在应用或系统中正确解析和渲染淘宝商品详情API接口返回的HTML内容?
  • Chromium 132 编译指南 Windows 篇 - 生成构建文件 (六)
  • Portainer.io安装并配置Docker远程访问及CA证书
  • 腾讯云AI代码助手编程挑战赛-百事一点通
  • LabVIEW光流跟踪算法
  • Shell 脚本与 Pytest 结合:交替运行 Pytest 的两个测试方法
  • 【初阶数据结构】线性表之单链表
  • 数据结构的插入与删除
  • 基于单片机的无线遥控篮球比赛记分器的设计研究
  • Vue CLI 通过 NODE_ENV 确定当前是开发还是生产环境
  • 【笔记整理】记录参加骁龙AIPC开发者技术沙龙的笔记
  • MYSQL8创建新用户报错:You have an error in your SQL syntax;check...
  • 【Ubuntu与Linux操作系统:十二、LAMP平台与PHP开发环境】
  • 前端基础技术全解析:从HTML前端基础标签语言开始,逐步深入CSS样式修饰、JavaScript脚本控制、Ajax异步通信以及WebSocket持久通信
  • 微服务滚动法布
  • 25/1/13 嵌入式笔记 继续学习Esp32