c++ 类和对象

目录

  • 基本概念
  • 类的定义
  • 类的基本使用
    • 对象的实例化
    • 访问控制符
  • 面向对象程序设计方法
    • 实例
  • 构造函数和析构函数
    • 构造函数
      • 定义
      • 总结
    • 析构函数
      • 定义
      • 作用
    • 多个对象构造和析构
  • 对象的动态建立和释放
    • new和delete
    • new delete和malloc free区别
  • 对象的赋值
    • 利用实例化好的对象对另外一个对象初始化
    • 拷贝构造函数
  • 浅拷贝和深拷贝
    • 浅拷贝
    • 深拷贝
  • 引用作为形参
  • 面向对象内存模型
    • 编译器对属性和方法的处理机制
    • this指针
  • 静态成员属性和方法
    • 静态成员属性
    • 静态成员函数
  • string类
    • 简述
    • 常见构造方法
    • 赋值
    • 拼接
    • 比较大小
    • 求字串
    • 常用函数
      • 查找子串和字符
      • 替换子串
      • 删除子串
      • 插入字符串
  • 动态数组设计

基本概念

存在自身的属性、行为,封装在class

类是抽象的,对象是具象的

对象是由类实例化而来的

类对于某个事物的描述是抽象的,类是对一个事物的一个描述而已
操作的某类事物中一个或者多个具体的食物,就是称为对象

类的定义

属性:定义

行为:函数/方法

class name{
访问控制符:成员变量成员函数
}
访问控制符有 public private protected```cpp
class Animal{
public:int age;char name[32];void jiao(const char *voice){std::cout<<name<<":"<<voice<<std::endl;}
};
  • 类的首字母一般大写 大驼峰写法
  • 访问控制符后续细说

类的基本使用

对象的实例化

实例化普通对象

Animal cat; //一个实例化的对象

使用数组实例化多个普通对象

Animal cats[10];

定义一个指针变量

Animal *cat;
//指针变量不是一个类的实例化对象,本质是一个指针。定义一个类的指针变量根本就没有实例化一个对象

类的实例化方法还有,后续继续

例子:

class Animal{
public:int age;char name[32];void jiao(const char *voice){std::cout<<name<<":"<<voice<<std::endl;}
};int main() {Animal dog;dog.age=18;// 清零memset(dog.name,0,sizeof(dog.name));// 赋值strcpy(dog.name,"xiaohu");dog.jiao("wang wang");return 0;
}

访问控制符

给成员变量和方法定义访问级别

  • public 公开的,类的内部和外部都可以访问到变量和方法,还有继承。。。
  • private 私有的,只有类的内部可以访问到变量和方法,继承。。。
  • protected 保护的,只有类的内部可以访问到变量和方法,继承。。。
class Teacher{
public:char name[32];void set_age(int age){if(age>200 || age<0) { // 阈值判断   函数形参合法性检查std::cout<<"age error"<<std::endl;return;}_age=age; // 在类的内部访问private成员变量}int get_age(){if(_age){return _age;}return 0; // 0代表age不存在}
private:int _age;
};Teacher t;memset(t.name,0,sizeof(t));strcpy(t.name,"三哥");//t._age=18;   错误的t.set_age(54);std::cout<<t.get_age()<<std::endl;

面向对象程序设计方法

面向过程程序设计:数据结构+算法

  • 用户需求简单而固定

特点

  • 分析解决问题所需的步骤
  • 利用函数实现各个步骤
  • 依次调用函数解决问题

问题

  • 软件可重用性差
  • 软件可维护性差

面向对象程序设计

  • 属性:静态特征,可以用某种数据来描述
  • 方法:动态特征,对象所表现的行为或具有的功能

特点

  • 直接分析用户需求中涉及的各个实体
  • 在代码中描述现实世界的实体
  • 在代码中关联各个实体协同工作解决问题

优势

  • 构建的软件能适应用户需求的不断变化

三大特征

  • 封装

    • 把变量(属性)和函数(方法)合成一个整体,封装在一个类中
    • 尽可能隐蔽对象内部的细节。对外形成一个边界,只保留有限的对外接口与外部发生联系
    • 对变量和函数进行访问控制,保证数据的安全性
  • 继承

  • 多态

实例

// Box.h
#ifndef C___BOX_H
#define C___BOX_H
class Box {
private:int _l,_w,_h,_s,_v;
public:void set_l(int l);void set_w(int w);void set_h(int h);int get_l();int get_w();int get_h();int get_s();int get_v();
};
#endif //C___BOX_H// Box.cpp
#include "Box.h"
#include "iostream"
void Box::set_l(int l) {if(l<0){std::cout<<"l error"<<std::endl;return;}_l=l;
}
void Box::set_w(int w) {if(w<0){std::cout<<"w error"<<std::endl;return;}_w=w;
}
void Box::set_h(int h) {if(h<0){std::cout<<"h error"<<std::endl;return;}_h=h;
}int Box::get_l() {return _l;
}
int Box::get_w() {return _w;
}
int Box::get_h() {return _h;
}// 先判断长宽高是否存在 然后在计算 这里没有实现
int Box::get_s() {return 2*(_l*_h+_l*_w+_h*_w);
}
int Box::get_v() {return _l*_w*_h;
}// main.cppBox b;b.set_l(15);b.set_h(5);b.set_w(5);std::cout<<"s:"<<b.get_s()<<std::endl;std::cout<<"v:"<<b.get_v()<<std::endl;

构造函数和析构函数

构造函数

类的属性在定义的时候不可以初始化

class Dog{
public:int age=18; // 这是不允许的
};

构造函数(constructor)处理对象的初始化,特殊的成员函数,实例化对象的时候自动调用构造函数,作用就是在类实例化的时候初始化成员变量

定义

与类名相同的特殊成员函数 即为构造函数
在定义的时候可以有参数,也可以没有参数
没有任何返回类型的声明
构造函数要在外部可以访问到 public

class Dog{
public:
/*
默认构造函数:如果构造函数没有被定义,编译器会自动生成一个如下的构造函数(我们没有写构造函数的时候才会自动生成)
*/Dog(){}
};// 实例
class Dog{
public:
//无参数构造函数Dog(){std::cout<<"Dog"<<std::endl;}Dog(int age,int id){std::cout<<age<<"-"<<id<<std::endl;}
private:int _age;char name[50];
};Dog d1;  //一次Dog d2[4]; //四次//不是实例化一个对象,而是声明一个函数 返回值是Dog 名字是d3  形参列表为空Dog d3();Dog d5(1,2); //实例化对象 只调用相应的有两个int形参的调用函数

初始化成员列表

  • 由逗号分割的初始化列表组成
  • 数据成员的名称为mdata,并需要初始化为val 写法 mdata(val)
    Dog(int id,int num,int age):_id(id),_num(num),_age(age){std::cout<<"Dog:"<<std::endl;}

作用

  • 对类属性为引用时进行初始化 一个构造函数为引用初始化后,后续的构造函数都要进行
  • const修饰的成员变量进行初始化
  • 一个类中实例化另外一个类

调用 Dog d 的时候内存已经分配空间了,此时在构造函数体内部进行的是赋值而不是初始化,利用冒号即是初始化

class C{
public:int x;C(int s){x=s;}
};
// 类中实例化一个类
class B{
public:int a;C n;B():a(1),n(50){}
};//如果下面则是错误的
class B{
public:int a;C n;B():a(1){} // 报错  error: no matching function for call to 'C::C()'
};

总结

  • 构造一个对象一定会自动调用一个构造函数
  • 如果一个类中没有实现默认构造函数,编译器会自动生成一个(前提是没有实现任何带参数的构造函数)
  • 如果一个类中实现了带参数的构造函数,一定要实现一个无参的构造函数。因为如果在构造对象时不带参数将无法找到无参的构造函数导致编译失败
  • 构造函数可以有多个,根据构造对象时所传递的参数,会自动调用对应的构造函数
  • 类不会占用程序的内存空间,对象才会占用程序的内存空间
class B{}B b(); //不是实例化 一个返回class的b函数的声明
B (1,2);//是实例化

析构函数

定义

用于清理对象
语法:~ClassName()

  • 析构函数没有参数 没有任何返回类型的声明
  • 析构函数只有一个 不可以重载
  • 析构函数在对象销毁的时候自动调用
class Cat{
public:int age,id;char name[32];Cat(){std::cout<<"cat"<<std::endl;}~Cat(){std::cout<<"~~"<<std::endl;}
};// return 0;代表程序结束 也就是class要销毁了

作用

在栈空间的变量 函数等系统会自动销毁
而在堆空间我们申请的空间系统不会自动销毁,要使用析构函数进行销毁

class Cat{
public:int age,id;char *name;Cat(){std::cout<<"Cat()"<<std::endl;name=(char*) malloc(32); // 32B的空间 分配在堆上}Cat(char *name1){std::cout<<" Cat(char *name1)"<<std::endl;int len = strlen(name1);//分配在堆上name=(char *) malloc(len+1);strcpy(name,name1);}~Cat(){std::cout<<"~~"<<std::endl;if (name!=NULL){free(name);}}
};

多个对象构造和析构

当类中的成员变量是另外一个类的实例化对象,成员对象

成员变量所属的类中没有实现无参构造函数的时候,用初始化成员列表

class ABC{
public:ABC(int x,int y,int z){std::cout<<"ABC(int x,int y,int z)"<<std::endl;}~ABC(){std::cout<<"~ABC()"<<std::endl;}
};class MyD{
public:MyD(): abc1(1,2,3), abc2(1,1,1){std::cout<<"MyD()"<<std::endl;}~MyD(){std::cout<<"~MyD()"<<std::endl;}ABC abc1,abc2;
};/*
当实例化MyD时,会先构造成员对象(按照定义顺序),然后再构造MyD自身
当销毁的时候,先销毁MyD 然后再销毁成员对象(与定义顺序相反)
*/
MyD y;// 先输出两个ABC(int x,int y,int z) 分别时abc1 abc2的 然后输出MyD()// 销毁的时候  ~MyD()  然后两个~ABC() 分别时abc2 abc1的

也就是说
内部准备好 外部才可以准备(构造过程,内部按定义准备
外部销毁了 内部才可以销毁(析构过程,内部反定义销毁

对象的动态建立和释放

在c语言中使用malloc和free
在c++中一般使用 new delete

new和delete

基本语法使用

new

//new动态分配堆内存
使用形式:指针常量 = new 类型(常量);指针常量 = new 类型[表达式];
作用:从堆分配一块类型大小的存储空间,返回首地址
其中:常量是初始化的值可省略创建数组对象时,不能为对象指定初始值 // 例子
//在堆内存申请一个int(4b)大小的空间,并初始化为10
int *p = new int(10);//在堆内存申请四个int(4*4b)大小的空间
int *q = new int[4];// 在堆上申请一个Box类型大小的空间,会进行实例化对象
Box *x = new Box;Box *y = new Box(10,10,10);

在这里插入图片描述

delete

防止内存泄漏

delete 释放已分配的堆内存空间
使用形式:delete 指针变量;delete[] 指针变量;其中:指针变量 必须是new返回的指针	delete x;
delete[] xs;

new delete和malloc free区别

c++为了兼容c保留了malloc和free,但是不建议使用。
注意:new和delete是运算符,不是函数,因此执行效率更高

  • malloc/free是c的标准库的函数,new/delete是c++的运算符。调用函数要有函数调用栈 有消耗比运算符效率低

  • new能自动计算需要分配的内存空间,而malloc需要手动计算字节数

    • int *p = new int[4]; int *q = (int *)malloc(4*sizeof(int));
  • new和delete直接带具体类型的指针,而malloc和free返回void类型的指针(强制类型转化)

    • int *p = new int[4]; int *q = (int *)malloc(4*4); malloc 要强制类型转化
  • new类型是安全的,malloc不是。

  • new 调用构造函数 而malloc不能 malloc可能给一些无法初始化

  • delete 调用析构函数 而free不能 free可能导致内存泄露

区别在以下几个方面

  • 效率 运算符 函数
  • 计算空间 自动计算 手动计算
  • 类型 具体类型指针 void类型指针
  • 安全 类型安全 类型不安全
  • 是否能调用构造 析构函数

对象的赋值

利用实例化好的对象对另外一个对象初始化

会存在一些问题!! 如果类里面成员变量有指针会出现问题,同一指针指向同一空间
如下代码和图片

class Test{
public:int x,y;int *sum;Test(){std::cout<<"Test()"<<std::endl;x=0;y=0;sum = new int[4];}Test(int a,int b):x(a),y(b){std::cout<<"Test(int a,int b)"<<std::endl;sum = new int[4];}
};Test *t1 = new Test(10,10);Test t2 = *t1;std::cout<<t1->x<<std::endl;std::cout<<t2.x<<std::endl;for (int i =0;i<4;++i){t1->sum[i]=i;}std::cout<<t2.sum[0]<<std::endl;// 手动销毁t1开辟的堆空间-- 意味着销毁*t1这个对象 自动调用析构函数 顺带手动释放成员变量申请的堆地址delete t1;//此时再访问t2的sum,数据会乱 因为指向了被回收的空间 // 除此t1销毁的时候释放sum空间  但在t2销毁的时候又释放一次sum,造成了同一块堆空间的二次释放  第二次释放的时候会出现异常 后续的代码就不会正常执行std::cout<<t2.sum[0]<<std::endl;

在这里插入图片描述
那么怎么解决上述问题?

一种方法:手动

Test t2;
t2.x=t1.x;
t2.y=t1.y;
for (int i=0;i<4;++i)t2.sum[i]=t1.sum[i];

另外方法:拷贝构造函数

拷贝构造函数

当使用Test t2=t1的时候,不会调用构造函数,而是调用拷贝构造函数(如果我们没有写,编译器自动生成一个拷贝构造函数)

class Test{
public:int x,y;int *sum;
...// 拷贝构造函数Test(const Test &t){ // 参数是引用的右值 此例子中也就是t1的引用std::cout<<"Test(const Test &t)"<< std::endl;/** 编译器自动帮我们实现的是:*  x=t.x;*  y=t.y;*  sum=t.sum;* */x = t.x;y = t.y;sum=new int[4]; // 新开辟一段空间// 将t1.sum空间的内容拷贝到sum所指向的空间for(auto i=0;i<4;++i)sum[i]=t.sum[i];}
};Test t1(10,10);t1.sum[0]=100;t1.sum[1]=101;t1.sum[2]=102;t1.sum[3]=103;Test t2=t1;//地址不同std::cout<<t1.sum<<std::endl;std::cout<<t2.sum<<std::endl;

1、为什么拷贝构造函数的形参是引用?Test(const Test &t)

因为如果是这样的话Test(const Test t),也就是会调用一下Test t = t1这样会触发拷贝构造函数,会造成无限循环调用拷贝构造函数,所以必须是引用。
除此 还会新开辟空间生成t1 造成空间浪费

2、为什么拷贝构造函数的形参是必须用const修饰?Test(const Test &t)

保护右值,即防止t1对象被修改

浅拷贝和深拷贝

浅拷贝

同一类型的对象之间可以赋值,使得两个对象的成员变量的值相同,两个对象依然是独立的两个对象,这种情况叫做浅拷贝

一般情况,浅拷贝没有任何副作用,但是当成员变量有指针,并且指针指向动态分配的内存空间,这样的浅拷贝会导致两个对象的指针指向同一空间,当两个对象销毁的时候会调用析构函数,造成同一空间被释放两次从而导致程序运行出错。

如果我们没有实现拷贝构造函数,c++编译器会自动实现一个拷贝构造函数,是默认拷贝构造函数 是浅拷贝。
在这里插入图片描述

深拷贝

自己手动实现拷贝构造函数,在拷贝构造函数中需要对对象中的指针变量进行单独的内存申请。
两个对象中的指针变量不会指向同一块内存空间,然后再将右值对象指针所指向的空间中的内容拷贝到新的对象指针所指向的堆空间中。

在这里插入图片描述

引用作为形参

好处

中间没有临时对象的产生,提高了程序执行的效率。

注意事项

防止值被修改,也就是为了保护传入的值,应该const修饰 使其为只读

面向对象内存模型

编译器对属性和方法的处理机制

在c语言中,数据和处理数据的操作(函数)是分开声明的,也就是说,语言本身并没有数据和函数的关联性。
在c++中,通过抽象数据类型,在类中定义数据和函数,实现数据和函数直接的绑定

class C1{
public:int x;int y;int k;
protected:
private:
};
class C2{
public:int x,y,k;int getK(){return k;}void setL(int mK){k=mK;}
};C1 c1;C2 c2;std::cout<<"c1:"<<sizeof(c1)<< std::endl; //12std::cout<<"c2:"<<sizeof(c2)<< std::endl; //12

上面的代码 输出的c1和c2的占用空间大小竟然是相同的!!

也就是说,C++类对象中的成员变量和成员函数是分开存储的

成员变量

  • 普通成员变量:存储在对象中(栈),与struct变量有相同的内存布局和字节对齐方式
  • 静态成员变量:存储在全局数据区

成员函数

  • 存储在代码段

内存从上到下可以大致分为:栈区 堆区 数据段 代码段

this指针

所有类实例化的对象共享处于代码段中的成员函数,但是成员函数怎么直到是谁调用的它呢?这就引出了this指针

this指针就是指向调用该成员函数的对象

gdb调试

    C1 c1;c1.k=10;C2 c2;c2.k=100;c2.getK();

1、g++ -g main.cpp -o main
2、gbd main
3、start n(next)print c2.getK quit(退出)

在这里插入图片描述
在这里插入图片描述

这里的参数就是this指针 编译器自动生成的,this指针指向调用方法的对象

c.getK();getK(&c);  传入对象c的地址,传给了C *const this(成员函数的第一个形参)  this指向c的地址

静态成员属性和方法

静态成员属性

  • 关键字 static 声明一个类的成员

  • 静态成员提供一个同类对象的共享机制

  • 这个类无论有多少个对象被创建,这些对象共享这个static成员

  • static的作用域是类和对象之间,但不是对象的成员

  • 调用

    • 对象.静态成员属性
    • 类::静态成员属性 (推荐,可读性强)
class Sheep{
public:char name[55];int age;static int cnt; //这里只是声明 定义和初始化要放到全局Sheep(){cnt++;}~Sheep(){cnt--;}
};
int Sheep::cnt;//定义sheep类的静态成员变量cnt 并且初始化(如果不初始化默认为0)// main函数Sheep *p = new Sheep[10];//访问静态成员变量std::cout<<Sheep::cnt<<std::endl;std::cout<<p->cnt<<std::endl;

静态成员函数

  • 使用static修饰的成员函数

  • 在静态成员函数内不能访问除静态成员变量以外的其他成员变量(只能访问静态成员变量

    • 因为静态成员函数没有this指针,它不是类的成员
  • 调用方法

    • 对象.静态成员函数()
    • 类::静态成员函数() (推荐,可读性强)
class Sheep{
public:char name[55];int age;static int cnt; //这里只是声明 定义和初始化要放到全局//静态成员函数static int sheepNum(){//std::cout<<age;//报错,静态成员函数不能访问非静态的成员变量return cnt; //静态成员属性}Sheep(){cnt++;}~Sheep(){cnt--;}
};int Sheep::cnt=0;//定义sheep类的静态成员变量cnt 并且初始化(如果不初始化默认为0)
// main函数中Sheep s1;std::cout<<Sheep::sheepNum();

存在的意义?

  • 如果静态成员属性是private 那么只能通过静态成员函数访问
  • 可以实现某些特殊的设计模式,如singleton(单例模式:一个类只能有一个对象)
  • 可以封装某些算法,比如数学函数(in sin cos tan 等等),这些函数本就么必要属于任何一个对象,所有直接从类上调用感觉更好

string类

简述

c语言中使用字符数组表示字符串的,这样效率比较低
C++标准库力通过 类string 重新自定义了字符串

#include <string>

  • 支持直接字符串连接
  • 支持直接字符串大小比较
  • 支持直接字串查找和提取
  • 支持直接字符串的插入和替换
  • 具备字符串数组的灵活性,可以通过下标来访问每个字符

常见构造方法

    std::string s;//空字符串std::string s1("hello"); //用字符串常量构造string对象  调用的构造函数 string(const char*)std::string s2(4,'k');//kkkkstd::string s3("123456",1,3);//从str下标为pos的开始去n个字符  从"123456" 下标为1的2数3个字符std::cout<<s.size()<<std::endl; //字符串长度std::cout<<s.length()<<std::endl; //字符串长度//下面是错误的
std::string s4('A'); //传入一个char类型
std::string s5(123); //传入一个int类型
std::string s6(123.2365); //传入一个double类型

赋值

1、可以使用char*类型的变量、常量,char类型的常量对string进行赋值

    std::string s;s = "hello";s='A'; //赋值的是字符A 但是s是字符串char name[32];strcpy(name,"du");s=name;

2、assign成员函数

    std::string s1("string"),s2;s2.assign(s1);//s2=s1s2.assign("ddddd");s2.assign(s1,1,3);//s2=s1下标从1开始 取3个s2.assign(3,'a');//aaa

拼接

// 直接使用 + std::string s1("+"),s2;s2 = '1'+s1+'2'; //1+2to_string(val); //将int double bool转化为string// append成员函数,返回对象自身的引用s2.append(s1); // 将s1追加到s2后面 s2=s2+s1s2.append(s1,1,3); //下标 1  数量 3(追加字串一般用append)s2.append(3,'k'); // 追加3个k

比较大小

1、直接使用比较的运算符比较大小(基于ascii比较)

string s1("hello"),s2("world");
bool ret = s1>s2;

2、compare成员函数

  • 小于0 表示当前的字符串小于传入的的字符串
  • 等于0 表示当前的字符串等于传入的的字符串
  • 大于0 表示当前的字符串等于传入的的字符串

主要是用于指定字符串的子串进行比较大小

s1.compare(1,3,s2,1,3);  //s1从下标1开始数3个字符的字串与s2从下标1开始数3个字符的字串比较

求字串

substr成员函数可以用于求子串,函数原型:

string substr(int n=0,int m=string::npos) const;

	string s1 = s.substr(0, 2);//从s的索引为0的位置截取2个长度的字符串string s2 = s.substr(2, 3);//从s的索引为2的位置截取3个长度的字符串string s3 = s.substr(2);//如果只提供一个索引位置信息,那么截取s索引为2到字符串尾部string s4 = s.substr();//如果不提供任何信息,那么等价于s3=sstring s5 = s.substr(7);//按理s的索引最多到6,但是组成字符串默认最后一位为空字符,所以索引可以到7

常用函数

查找子串和字符

查不到返回string::npos,是string定义的一个静态常量

  • find:从前往后查找字串或字符出现的位置 *(比较重要)
  • rfind:从后往前查找字串或字符出现的位置
  • find_first_of:从前往后查找何处第一次出现另一个字符串中包含的字符
  • find_last_of:从后往前查找何处第一次出现另一个字符串中包含的字符
  • find_first_not_of:从前往后查找何处第一次出现另一个字符串中没有包含的字符
  • find_last_not_of:从后往前查找何处第一次出现另一个字符串中没有包含的字符

替换子串

查不到返回string::npos,是string定义的一个静态常量

replace成员函数可以对string对象中的字串进行替换,返回对象自身的引用

replace(int pos,int n,string s,[int pos],[int n]);

//c++ 对单引号和双引号区分特别严重
string s("hello world");
s.replace(1,4,"i"); //hi world
s.replace(1,1,2,'i'); //hii world
s.replace(1,2,"abcdefghijk",8,1);//hi world

删除子串

erase删除string对象的子串,返回对象自身的引用

string s("real dog");
s.erase(0,4);// dog   删除从下标0开始 4个字符
s.erase(2);// d       删除从下标2开始到结尾的全部字符// 删除字符串中的steel// 删除字符串中的steelstd::string s("sdjaldsteeldsakdssteel"),moom("steel");while (s.find(moom)!=std::string::npos){s.erase(s.find(moom),moom.length());}std::cout<<s<<std::endl;

插入字符串

insert 成员函数可以在 string 对象中插入另一个字符串,返回值为对象自身的引用

string s("limit");
s.insert(2,"123");//li123mit 在1-2之间插入
s.insert(1,5,'x');//lxxxxxi123mit 在0-1之间插入5个x
s.insert(3,"hello",1,3);// 在2-3之间插入hello 1到1之后的3个 子串

动态数组设计

Array.h

//
// Created by DELL on 2024-01-04.
//#ifndef ARRAY_ARRAY_H
#define ARRAY_ARRAY_H
#define DefaultLen 4using u32_t = unsigned int;
class Array {
private:int *data;u32_t length; //数组当前长度u32_t capacity;//数组容量static int indexMax;//自动扩容函数void extend();
public://默认构造函数Array();//带参数的构造函数Array(u32_t len);//拷贝构造函数Array(const Array &arr);//析构函数~Array();//获得数组当前长度u32_t getLength();//获取数组容量u32_t getCapacity();//返回指定位置的值int getValue(u32_t index);//返回指定值的下标int getIndex(int value);//销毁动态数组void destroy();//在指定位置插入元素bool insert(u32_t i,int value);//删除指定位置元素void remove_index(u32_t i);//删除指定值的元素void remove_value(int value);
};#endif //ARRAY_ARRAY_H

Array.cpp

//
// Created by DELL on 2024-01-04.
//
#include <iostream>
#include "Array.h"
#include "string"
int Array::indexMax = 999999;
using namespace std;
Array::Array() {this->data=new int[DefaultLen];//默认分配4个int类型的空间this->length=0; //当前长度为0this->capacity=DefaultLen;//容量为DefaultLen
}Array::Array(u32_t len){this->data=new int[len];this->length=0;this->capacity=len;
}//拷贝构造函数 实现深拷贝
Array::Array(const Array &arr) {this->data=new int [arr.capacity];this->length = arr.length;this->capacity = arr.capacity;for (int i = 0; i < length; ++i) {this->data[i]=arr.data[i];}
}Array::~Array() {if(this->data!= nullptr){delete[] this->data;}
}void Array::extend() {//临时指针保存堆空间的首地址int * tmp = data;data = new int [2*capacity];for (int i = 0; i < length; ++i) {data[i] = tmp[i];}delete[] tmp;capacity *=2;
}void Array::destroy() {if (data){delete[] data;data= nullptr; // 这里将data指针置空,防止析构函数二次销毁length=0;capacity=0;}
}u32_t Array::getLength() {return length;
}u32_t Array::getCapacity() {return capacity;
}int Array::getValue(u32_t index) {if(index<length) return data[index];cout<<"index out of range"<<endl;return indexMax;
}bool Array::insert(u32_t i, int value) {//i 和 capacity 的大小关系if(length==capacity)extend();if(i>=capacity){data[length] = value;}else{int j=length;for (; j > i; --j) {data[j] = data[j-1];}data[j]=value;}length++;return true;
}int Array::getIndex(int value) {for (int i = 0; i < length; ++i) {if (data[i]==value)return i;}cout<<"not find value:"<<value<<endl;return -1;
}void Array::remove_index(u32_t i) {if(i>=length){cout<<"index out of range"<<endl;return;}for (int j = i; j < length; ++j) {data[j] = data[j+1];}length--;
}void Array::remove_value(int value) {int pos = getIndex(value);while (pos>=0){remove_index(pos);pos= getIndex(value);}
}

main.cpp

#include <iostream>
#include "Array.h"
using namespace std;
/** Array动态数组设计,功能(存储整型数据)* 1.自动扩容* 2.销毁数组* 3.在指定位置插入元素* 4.删除指定位置的元素* 5.删除指定值的元素* */int main() {Array t(5);t.insert(0,0);t.insert(1,1);t.insert(2,2);t.insert(4,3);t.insert(4,4);t.insert(500,5);t.insert(8,0);//    t.remove_index(20);
//    t.remove_index(2);t.remove_value(0);
//    t.getValue(100);
//    t.destroy();for (int i = 0; i < t.getLength(); ++i) {cout<<t.getValue(i)<<ends;}cout<<endl;cout<<t.getLength()<<endl;cout<<t.getCapacity()<<endl;return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

力扣hot100 二叉树的直径

&#x1f468;‍&#x1f3eb; 题目地址 一个节点的最大直径 它左树的深度 它右树的深度 &#x1f60b; AC code /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* Tr…

5.云原生安全之ingress配置域名TLS证书

文章目录 cloudflare配置使用cloudflare托管域名获取cloudflare API Token在cloudflare中配置SSL/TLS kubesphere使用cert-manager申请cloudflare证书安装证书管理器创建Secret资源创建cluster-issuer.yaml创建cert.yaml申请证书已经查看申请状态 部署harbor并配置ingress使用证…

C++上位软件通过Snap7开源库访问西门子S7-200/合信M226ES数据块的方法

前言 上一篇文章中介绍了Snap7访问西门子S7-1200/S7-1500 DB块的方法&#xff0c;对于S7-200PLC是没有数据块访问的。S7-200PLC中Snap7只能通过访问MB块&#xff0c;VB块的方法进行和PLC之间的Snap7通信和数据交换。手头没有S7-200PLC故通过合信CTMC M226ES运动控制器进行测试&…

魔改版小市值策略

策略思路 最近几年&#xff0c;小市值策略一直都收益不错&#xff08;当然&#xff0c;不包含17年和18年&#xff09;。小市值因子对收益的影响是很大的。特别是行情不好的时候&#xff0c;大家都忙着炒作热点&#xff0c;那么这时候符合题材的小市值更加符合炒作标准了。 为…

Superset服务安装

文章目录 Superset概述Superset应用场景Superset安装及使用安装Python环境安装Miniconda下载Miniconda(Python3版本)安装Miniconda取消每次登陆自动激活conda base环境创建Python3.7(Superset)环境配置conda国内镜像创建Superset环境激活Superset环境查看python版本 Superset部…

AWS(三):如何在AwsManagedAd目录和windowsAD实例之间建立双向信任。

前提&#xff1a; 1.创建好了一个AWS managed AD目录&#xff0c;我的目录域名为:aws.managed.com 2.创建好了一个windows AD实例并提升了为域控服务器,实例域名为:aws2.com 看过我AWS 一和二的应该都会创建windows实例了&#xff0c;切记不能将其无缝加入到aws managed AD的…

Vue 模板编译原理解析

Vue 模板编译原理解析 模板编译整体流程 首先我们看一下什么是编译&#xff1f; 所谓编译&#xff08;Compile&#xff09;&#xff0c;指的是将语言 A 翻译成语言 B&#xff0c;语言 A 就被称之为源码&#xff08;source code&#xff09;&#xff0c;语言 B 就被称之为目标…

【QML】与 C++ 混合编程:互相调用函数

文章目录 qml 调用 C 函数案例 a&#xff1a;Q_INVOKABLE 标记 C 函数 视图设置进 qml 属性案例 b&#xff1a;qml 通过发送信号的方式&#xff0c;调用 Qt 槽函数 C调用qml函数 qml 调用 C 函数 qml 要使用 C 的函数有两个方法&#xff1a; 一种是&#xff0c;用 Q_INVOKABLE…

STM32 学习(三)OLED 调试工具

目录 一、简介 二、使用方法 2.1 接线图 2.2 配置引脚 2.3 编写代码 三、Keil 工具调试 一、简介 在进行单片机开发时&#xff0c;有很多调试方法&#xff0c;如下图&#xff1a; 其中 OLED 就是一种比较好用的调试工具&#xff1a; OLED 硬件电路如下&#xff0c…

7步教你如何快速建立电子商务网站

如果您需要以客户为中心搭建电子商务网站&#xff0c;或者您正在寻求开展电子商务业务&#xff0c;那么您很幸运——现在是开始的最佳时机&#xff01;事实上&#xff0c;在疫情期间&#xff0c;电子商务销售额增长了 50%。电子商务现在是一个价值 8700 亿美元的产业。随着如此…

深入了解Apache 日志,Apache 日志分析工具

Apache Web 服务器在企业中广泛用于托管其网站和 Web 应用程序&#xff0c;Apache 服务器生成的原始日志提供有关 Apache 服务器托管的网站如何处理用户请求以及访问您的网站时经常遇到的错误的重要信息。 什么是 Apache 日志 Apache 日志包含 Apache Web 服务器处理的所有事…

rime中州韵小狼毫 inputShow lua Filter 输入字符透传滤镜

在 rime中州韵小狼毫 inputShow lua Translator 一文中&#xff0c;我们通过 inputShow.lua 定制了 inputShow_translator&#xff0c;这使得我们的输入方案可以将用户输入的字符透传到候选列表中来。如下&#x1f447;&#xff1a; &#x1f446;上图中我们在候选列表中看到了…

音视频通信

文章目录 一、音视频通信流程二、流媒体协议1、RTSP2、RTMP3、HLS4、WebRTC 一、音视频通信流程 音视频通信完整流程有如下几个环节&#xff1a;采集、编码、前后处理、传输、解码、缓冲、渲染等。 每一个细分环节&#xff0c;还有更细分的技术模块。比如&#xff0c;前后处…

[足式机器人]Part2 Dr. CAN学习笔记-Ch01自动控制原理

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-Ch01自动控制原理 1. 开环系统与闭环系统Open/Closed Loop System1.1 EG1: 烧水与控温水壶1.2 EG2: 蓄水与最终水位1.3 闭环控制系统 2. 稳定性分析Stability2.1 序言2.2 稳定的分类2.3 稳定的对…

[蓝桥杯2020国赛]答疑

答疑 题目描述 有 n 位同学同时找老师答疑。每位同学都预先估计了自己答疑的时间。 老师可以安排答疑的顺序&#xff0c;同学们要依次进入老师办公室答疑。 一位同学答疑的过程如下&#xff1a; 首先进入办公室&#xff0c;编号为 i 的同学需要 si​ 毫秒的时间。然后同学问…

2020年认证杯SPSSPRO杯数学建模D题(第一阶段)让电脑桌面飞起来全过程文档及程序

2020年认证杯SPSSPRO杯数学建模 D题 让电脑桌面飞起来 原题再现&#xff1a; 对于一些必须每天使用电脑工作的白领来说&#xff0c;电脑桌面有着非常特殊的意义&#xff0c;通常一些频繁使用或者比较重要的图标会一直保留在桌面上&#xff0c;但是随着时间的推移&#xff0c;…

Java数据结构:1. 数据结构前置知识

文章目录 一、初识数据结构二、初识集合框架1. 什么是集合框架2. 集合框架的重要性3. 背后所涉及的数据结构以及算法 三、时间复杂度空间复杂度1. 算法效率2. 时间复杂度&#xff08;1&#xff09;概念&#xff08;2&#xff09;大O的渐进表示法&#xff08;3&#xff09;推导大…

捕捉“五彩斑斓的黑”:锗基短波红外相机的多种成像应用

红外处于人眼可观察范围以外&#xff0c;为我们了解未知领域提供了新的途径。红外又可以根据波段范围&#xff0c;分为短波红外、中波红外与长波红外。较短的SWIR波长——大约900nm-1700nm——与可见光范围内的光子表现相似。虽然在SWIR中目标的光谱含量不同&#xff0c;但所产…

PostgreSQL荣获DB-Engines 2023年度数据库

数据库流行度排名网站 DB-Engines 2024 年 1 月 2 日发布文章宣称&#xff0c;PostgreSQL 荣获 2023 年度数据库管理系统称号。 PostgreSQL 在过去一年中获得了比其他 417 个产品更多的流行度增长&#xff0c;因此获得了 2023 年度 DBMS。 DB-Engines 通过计算每种数据库 2024 …

Amazon CodeWhisperer 免费 AI 代码生成助手体验分享

今年上半年&#xff0c;亚马逊云科技正式推出了实时AI编程助手 Amazon CodeWhisperer&#xff0c;还提供了供所有开发人员免费使用的个人版版本。经过一段时间的体验&#xff0c;我觉得 CodeWhisperer 可以处理编程工作中遇到的很多问题&#xff0c;并且帮助开发人员提高编程效…