c++补充

news/2024/5/14 16:32:08

构造函数、析构函数

#include <iostream>
using namespace std;// 构造函数、析构函数
//	---	"构造函数"类比生活中的"出厂设置"	---
//	---	"析构函数"类比生活中的"销毁设置"	---
// 如果我们不写这两种函数,编译器会提供默认的构造函数和析构函数,但是它们是空实现
class Person
{
private:int age;public:// 构造函数(无参)Person(){cout << "构造函数的调用,无参" << endl;}// 构造函数(含参)Person(int a){age = a;cout << "构造函数的调用, 含参" << endl;}// 构造函数(拷贝)Person(const Person& p){this->age = p.age;cout << "构造函数的调用,拷贝" << endl;}// 析构函数~Person(){cout << "析构函数的调用" << endl;}// 查看年龄int getAge() { return age; }
};void test()
{// 括号法//Person p1;		// 默认构造函数调用//Person p2(10);	// 括号法调用构造函数(含参)//Person p3(p2);	// 括号法调用构造函数(拷贝)//cout << p3.getMoney() << endl;	// 结果:10// 显示法Person p1;Person p2 = Person(10);		// 含参构造Person p3 = Person(p2);		// 拷贝构造// 注意事项 1:// Person(10);  // 匿名对象 -- 特点: 当前执行结束后,系统会立即回收掉匿名对象// 注意事项 2:// 不要利用拷贝构造函数去初始化匿名对象,即:Person(p3) 是不对的,// 编译器会认为 Person (p3) === Person p3;// 隐式转换法Person p4 = 10;		// 相当于写了 Person p4 = Person(10);   含参构造Person p5 = p4;		// 相当于写了 Person p5 = Person(p4);   拷贝构造
}int main()
{test();
}

初始化列表

#include <iostream>
using namespace std;// 初始化的方式
//	1. 传统的初始化
//	2. 初始化列表class Person
{
public:int age;int height;/*// 1. 传统初始化操作Person(int a, int b){age = a;height = b;}*/// 2. 初始化列表Person(int a, int b) :age(a), height(b){;	// 用";"表示空语句,仅起占位的作用}
};void test()
{	Person man(28, 180);cout << man.age << endl << man.height << endl;
}int main()
{test();
}

常函数、常对象

#include <iostream>
using namespace std;class Person
{
public:// 常函数:// this指针的本质是"指针常量",指针的指向是不可以修改的// const Person * const this;// 在成员函数后面加 const,修饰的是this指向,让指针指向的值也不可以修改void showPerson() const		// 函数的后面加了一个const,我们称为"常函数"{age = 30;  // 这段代码本质是 this->age = 30; 它是会报错的,因为它不可以修改height = 180;	// 如果非得要修改,请在定义的时候,在前面加上关键字 mutable}// 普通成员函数void change(){age = 40;height = 166;}int age;mutable int height;
};void test1()
{Person p;p.showPerson();
}void test2()
{// 常对象:// 在对象前加上 const,它将变为常对象const Person p;p.age = 22;		// 这里会报错,因为它不允许被修改p.height = 175;		// 这里不会报错,因为 mutable 修饰的 height 是一个特殊的变量// 常对象只能调用常函数p.showPerson();p.change();		// 常对象不可以调用普通成员函数,因为普通成员函数可以修改属性
}int main()
{test1();test2();
}

运算符重载

+ 运算符 重载

#include <iostream>
using namespace std;class Person
{
public:int age;int height;// 通过成员函数进行重载+号// Person p3 = p1 + p2; == Person p3 = p1.operator+(p2);Person operator+(const Person &p){Person temp;temp.age = this->age + p.age;temp.height = this->height + p.height;return temp;}
};// 通过全局函数重载+号
// Person p3 = p1 + p2; == Person p3 = operator+(p1, p2);
Person operator+(const Person& p1, const Person& p2)
{Person temp;temp.age = p1.age + p2.age;temp.height = p1.height + p2.height;return temp;
}void test()
{Person p1;p1.age = 22;p1.height = 166;Person p2;p2.age = 28;p2.height = 134;Person p3 = p1 + p2;	// 加号运算符重载,让编译器知道如何进行运算cout << p3.age << endl << p3.height << endl;	// 输出结果:50、300Person p3 = p3 + 66;	// 编译器不知道如何运行,将会报错!// 运算符重载,也可以使用"函数重载":// 我们可以通过"全局函数重载"实现一个 Person operator+(const Person& p1, int num) {...}// 或者可以通过"成员函数重载"实现一个 Person operator+(int num) {...}// 注意事项:// 1. 对于内置的数据类型的表达式的运算符是不可能改变的// 2. 不用滥用运算符重载
}int main()
{test();
}

<< 运算符 重载

#include <iostream>
using namespace std;class Person
{friend ostream& operator<<(ostream&, const Person&);public:Person(int age, int height) :age(age), height(height){cout << "调用了构造函数" << endl;}private:int age;int height;
};// 无法通过成员函数进行重载<<号
// 只能通过全局函数重载<<号
ostream& operator<<(ostream& cout, const Person& p)
{cout << "[ age = " << p.age << ", height = " << p.height << " ]";return cout;
}void test()
{Person p1(22, 166);cout << p1 << endl;	// 输出结果:[ age = 22, height = 166 ]
}int main()
{test();
}

自增运算符 重载

#include <iostream>
using namespace std;class MyInteger
{friend ostream& operator<<(ostream&, MyInteger);public:MyInteger(int a) :num(a){cout << "调用了构造函数" << endl;}// 前置递增MyInteger& operator++(){num++;return *this;}// 后置递增MyInteger operator++(int)	// int 代表占位参数,可以用于区分前置和后置递增{// 先记录当前结果MyInteger temp = *this;// 后将自己进行递增num++;return temp;}private:int num;
};ostream& operator<<(ostream& cout, MyInteger obj)
{cout << obj.num;return cout;
}void test()
{MyInteger myint = 0;cout << ++(++myint) << endl;	// 输出:2cout << myint << endl;			// 输出:2cout << myint++ << endl;		// 输出:2cout << myint<< endl;			// 输出:3
}int main()
{test();
}

赋值运算符 重载

#include <iostream>
using namespace std;class Person
{
public:Person(int age){this->age = new int(age);}~Person(){if (age != NULL){delete age;age = NULL;}}// 赋值运算符重载Person& operator=(const Person& obj){*age = *obj.age;return *this;}int* age;
};void test()
{Person p1(10);cout << "p1的年龄为:" << *p1.age << endl;	// 输出结果:10Person p2(20);cout << "p2的年龄为:" << *p2.age << endl;	// 输出结果:20Person p3(30);cout << "p3的年龄为:" << *p3.age << endl;	// 输出结果:30// 这不是拷贝构造函数,拷贝构造函数也是一种构造函数// 这里是赋值语句,对象的赋值,编译器默认的行为是:将某对象的所有属性复制一份到另一个对象里面// 因为默认行为的直接复制,对于需要浅拷贝的内容没什么影响,但是对于需要深拷贝的内容影响很大// 为了避免恶劣影响,我们需要重载赋值运算符p3 = p2 = p1;cout << "修改后的p2的年龄为:" << *p2.age << endl;		// 输出结果:10cout << "修改后的p3的年龄为:" << *p3.age << endl;		// 输出结果:10
}int main()
{test();
}

关系运算符 重载

#include <iostream>
#include <string>
using namespace std;class Person
{
public:string name;int age;Person(string name, int age) :name(name), age(age){;	// 空语句}// == 关系运算符重载bool operator==(const Person& obj){if (name == obj.name && age == obj.age){return true;}return false;}// != 关系运算符重载bool operator!=(const Person& obj){if (name == obj.name && age == obj.age){return false;}return true;}};void test()
{Person p1("Jack", 18);Person p2("Jack", 18);Person p3("Tom", 18);if (p1 == p2)	cout << "p1 和 p2 相等" << endl;if (p1 != p3)	cout << "p1 和 p3 不相等" << endl;
}int main()
{test();
}

函数调用运算符 重载

#include <iostream>
#include <string>
using namespace std;class MyPrint
{
public:// 重载函数调用运算符void operator()(string text, string end="\n"){cout << text << end;}
};class MyAdd
{
public:// 重载函数调用运算符int operator()(int a, int b){return a + b;}
};void test()
{MyPrint print;MyAdd add;print("hello world");	// 由于使用起来非常类似于函数调用,因此称为仿函数string res = to_string(add(10, 20));print(res);// 匿名函数对象 -> MyAdd()cout << MyAdd()(100, 100) << endl;
}int main()
{test();
}

继承知识补充

在这里插入图片描述

多态

基础应用

#include <iostream>
#include <string>
using namespace std;class Animal
{
public:virtual void speak(){cout << "动物在叫" << endl;}
};class Cat :public Animal
{
public:void speak(){cout << "猫在叫" << endl;}
};class Dog :public Animal
{
public:void speak(){cout << "狗在叫" << endl;}
};// 地址早绑定,在编译阶段确定函数地址
// 如果想要传入的参数cat能够调用speak(),那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定
void doSpeak(Animal& animal)	// Animal &animal = cat;
{animal.speak();
}void test()
{Cat cat;Dog dog;doSpeak(cat);doSpeak(dog);
}int main()
{test();
}

进阶应用

#include <iostream>
#include <string>
using namespace std;class abstractDrinking
{
public:// 煮水virtual void Boil() = 0;// 冲泡virtual void Brew() = 0;// 倒入杯中virtual void PourInCup() = 0;// 加入辅料virtual void PutSomething() = 0;// 制作饮品void make(){Boil();Brew();PourInCup();PutSomething();}
};// 制作咖啡
class Coffee :public abstractDrinking	// 继承抽象类
{// 必须重写抽象类的纯虚函数,否则自己也会变成抽象类
public:// 煮水virtual void Boil(){cout << "煮熟自来水" << endl;}// 冲泡virtual void Brew(){cout << "冲泡咖啡" << endl;}// 倒入杯中virtual void PourInCup(){cout << "倒入迷你的咖啡杯中" << endl;}// 加入辅料virtual void PutSomething(){cout << "加入一些糖" << endl;}
};// 制作茶水
class Tea :public abstractDrinking	// 继承抽象类
{// 必须重写抽象类的纯虚函数,否则自己也会变成抽象类
public:// 煮水virtual void Boil(){cout << "煮熟矿泉水" << endl;}// 冲泡virtual void Brew(){cout << "冲泡茶叶" << endl;}// 倒入杯中virtual void PourInCup(){cout << "倒入经典的茶杯中" << endl;}// 加入辅料virtual void PutSomething(){cout << "加入一些香料" << endl;}
};// 制作饮料
void makeDrink(abstractDrinking* drink)
{drink->make();delete drink;			// 删除对象,释放内存
}void test()
{// 制作咖啡makeDrink(new Coffee);	// 开辟内存,创建对象// 制作茶makeDrink(new Tea);
}int main()
{test();
}

高级应用 (经典)

#include <iostream>
#include <string>
using namespace std;// ------------------
// 1. 抽象出每个零件(CPU、VideoCard、Memory)
// 2. 具体的厂商零件(Intel、Lenovo)
// 3. 电脑类->提供让电脑工作的函数(Computer)
// 4. 组装三台不同的电脑
// ------------------// 1. 抽象出每个零件
class CPU
{
public:// 抽象计算函数virtual void calculate() = 0;
};class VideoCard
{
public:// 抽象显示函数virtual void display() = 0;
};class Memory
{
public:// 抽象存储函数virtual void storage() = 0;
};// 2. 具体的厂商零件// --- Intel 的 CPU、VideoCard、Memory
class IntelCPU :public CPU
{
public:virtual void calculate()	// 也可以省略 virtual 关键字,直接写成 void calculate(){cout << "Intel 的 CPU 开始工作了" << endl;}
};class IntelVideoCard :public VideoCard
{
public:virtual void display(){cout << "Intel 的 VideoCard 开始工作了" << endl;}
};class IntelMemory :public Memory
{
public:virtual void storage(){cout << "Intel 的 Memory 开始工作了" << endl;}
};// --- Lenovo 的 CPU、VideoCard、Memory
class LenovoCPU :public CPU
{
public:virtual void calculate(){cout << "Lenovo 的 CPU 开始工作了" << endl;}
};class LenovoVideoCard :public VideoCard
{
public:virtual void display(){cout << "Lenovo 的 VideoCard 开始工作了" << endl;}
};class LenovoMemory :public Memory
{
public:virtual void storage(){cout << "Lenovo 的 Memory 开始工作了" << endl;}
};// 3. 电脑类
class Computer
{
public:// 构造函数中传入三个零件指针Computer(CPU* cpu, VideoCard* vc, Memory* mem) : cpu(cpu), vc(vc), mem(mem){;	// 空语句}// 提供工作的函数void work(){cpu->calculate();vc->display();mem->storage();}// 提供析构函数,销毁电脑的时候,释放3个电脑零件~Computer(){// 释放CPU零件if (cpu != NULL){delete cpu;cpu = NULL;}if (vc != NULL){delete vc;vc = NULL;}if (mem != NULL){delete mem;mem = NULL;}}private:CPU* cpu;		// CPU零件指针VideoCard* vc;	// 显卡零件指针Memory* mem;	// 内存条零件指针
};void test()
{// 4. 组装三台不同的电脑// 准备好'第一台电脑'的零件CPU* intelCpu = new IntelCPU;VideoCard* intelCard = new IntelVideoCard;Memory* intelMem = new IntelMemory;// 创建'第一台电脑'Computer* computer1 = new Computer(intelCpu, intelCard, intelMem);computer1->work();// 销毁'第一台电脑'delete computer1;computer1 = NULL;cout << "------------------------------" << endl;// 第二台电脑的组装Computer* computer2 = new Computer(new LenovoCPU, new LenovoVideoCard, new LenovoMemory);computer2->work();// 销毁'第二台电脑'delete computer2;computer2 = NULL;cout << "------------------------------" << endl;// 第三台电脑的组装Computer* computer3 = new Computer(new IntelCPU, new LenovoVideoCard, new LenovoMemory);computer3->work();// 销毁'第三台电脑'delete computer3;computer3 = NULL;
}int main()
{test();
}

文件操作

#include <iostream>
#include <fstream>
#include <string>using namespace std;// 文本文件
// 1. 写文本文件
// 2. 读文本文件// 二进制文件
// 1. 写二进制文件
// 2. 读二进制文件void writeText()
{// 1、包含头文件// 2、创建对象流ofstream file;// 3、打开文件,以追加的方式file.open("test.txt", ios::app);// 4、写内容file << "姓名:张三" << endl;file << "性别:男" << endl;file << "年龄:28" << endl;// 5、关闭文件file.close();
}void readText()
{// 1、包含头文件// 2、创建对象流ifstream file;// 3、打开文件,并判断是否打开成功file.open("test.txt", ios::in);if (!file.is_open()){cout << "文件打开失败!" << endl;return;}// 4、读取内容/*// 方法一:char arr[1024] = { 0 };		// 数组while (file >> arr){cout << arr << endl;}// 方法二:char arr[1024] = { 0 };		// 数组while (file.getline(arr, sizeof(arr))){cout << arr << endl;}// 方法三:string content;while (getline(file, content))		// 调用 <string> 里面的 getline() 方法{cout << content << endl;}*/// 方法四:(不建议)char c;while ((c = file.get()) != EOF)	// EOF: end of file{cout << c;		// 每次读取一个字符,将其输出}// 5、关闭文件file.close();
}class Person
{
public:char m_Name[64];int m_Age;
};void writeBinary()
{// 1、包含头文件// 2、创建流对象ofstream file;// 3、打开文件file.open("person.txt", ios::out | ios::binary);// 4、写文件Person p = { "张三", 28 };file.write((const char*)&p, sizeof(Person));// 5、关闭文件file.close();
}void readBinary()
{// 1、包含头文件// 2、创建流对象ifstream file;// 3、打开文件,判断文件是否打开成功file.open("person.txt", ios::in | ios::binary);if (!file.is_open()){cout << "文件打开失败" << endl;}// 4、读取文件Person p;file.read((char*)&p, sizeof(Person));cout << "姓名:" << p.m_Name << "年龄:" << p.m_Age << endl;// 5、关闭文件file.close();
}int main()
{writeText();readText();writeBinary();readBinary();
}

函数模板的重载

#include <iostream>
#include <string>
using namespace std;class Person
{
public:Person(string name, int age){this->m_Name = name;this->m_Age = m_Age;}string m_Name;int m_Age;
};template<typename T>
bool myCompare(T &a, T &b)
{if (a == b)	return true;else return false;
}// 模板的重载
template<>
bool myCompare(Person& p1, Person& p2)
{if (p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age)	return true;else return false;
}void test()
{int a = 10;int b = 10;bool ret = myCompare(a, b);cout << ret << endl;		// 输出结果:1Person p1("张三", 18);Person p2("李四", 28);bool res = myCompare(p1, p2);cout << res << endl;		// 输出结果:0
}int main()
{test();
}

类模板

#include <iostream>
#include <string>
using namespace std;// 类模板template<class Type1, class Type2 = int>	// 类模板在模板参数列表中可以有默认参数
class Person
{
public:Person(Type1 name, Type2 age){this->m_Name = name;this->m_Age = age;}void showPerson(){cout << "name: " << m_Name << " age: " << m_Age << endl;}Type1 m_Name;Type2 m_Age;
};void test()
{// ---类模板没有自动类型推导的使用方式Person<string, int> p1("张三", 18);p1.showPerson();// ---类模板在模板参数列表中可以有默认参数Person<string> p2("李四", 28);p2.showPerson();
}int main()
{test();
}
#include <iostream>
#include <string>
using namespace std;template<class T1, class T2>
class Person
{
public:Person(T1 name, T2 age){this->m_Name = name;this->m_Age = age;}void showPerson(){cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl;}T1 m_Name;T2 m_Age;
};// 类模板对象做函数参数// 1. 指定传入类型
void printPerson1(Person<string, int> &p)
{p.showPerson();
}// 2. 参数模板化
template<class T1, class T2>
void printPerson2(Person<T1, T2>& p)
{p.showPerson();
}// 3. 整个类
template<class T>
void printPerson3(T& p)
{p.showPerson();
}void test()
{Person<string, int> p1("张三", 28);printPerson1(p1);Person<string, int> p2("李四", 18);printPerson2(p2);Person<string, int> p3("王五", 38);printPerson3(p3);
}int main()
{test();
}

类模板与继承

#include <iostream>
#include <string>
using namespace std;// 类模板与继承
template <class T>
class Base
{T m_Name;
};// 必须要知道父类中的T类型,才能继承给子类
class Son : public Base<int>
{};void test1()
{Son s1;
}// 如果想灵活指定父类中T类型,子类也需要变类模板
template <class T1, class T2>
class Son2 : public Base<T2>
{
public:Son2(){cout << "T1 的类型为:" << typeid(T1).name() << endl;cout << "T2 的类型为:" << typeid(T2).name() << endl;}
};void test2()
{Son2<int, char> s2;
}int main()
{test1();test2();
}

类模板函数的类外实现

#include <iostream>
#include <string>
using namespace std;template<class T1, class T2>
class Person
{
public:Person(T1 name, T2 age);void showPerson();T1 m_Name;T2 m_Age;
};// 类模板成员的类外实现(构造函数)
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) :m_Name(name), m_Age(age)
{cout << "构造函数被调用了" << endl;
}
// 类模板成员的类外实现(普通成员函数)
template<class T1, class T2>
void Person<T1, T2>::showPerson()
{cout << "姓名:" << m_Name << "年龄:" << m_Age;
}void test()
{Person<string, int> p("Tom", 28);
}int main()
{test();
}

类模板分文件编写

问题:类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
解决:解决办法1:直接包含.cpp源文件解决办法2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,.hpp是约定的名称,并不是强制
  • main.cpp 文件
#include <string>
using namespace std;// 第一种解决方式:直接包含源文件
#include "person.cpp"// 第二种解决方式:将.h和.cpp中的内容写在一起,将后缀名改为.hpp文件(约定俗成)
// #include "person.hpp"void test()
{Person<string, int> p("Tom", 28);p.showPerson();
}int main()
{test();
}
  • person.cpp 文件
#include <iostream>
#include "person.h"// 类模板成员的类外实现(构造函数)
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) :m_Name(name), m_Age(age)
{std::cout << "构造函数被调用了" << std::endl;
}
// 类模板成员的类外实现(普通成员函数)
template<class T1, class T2>
void Person<T1, T2>::showPerson()
{std::cout << "姓名:" << m_Name << " 年龄:" << m_Age << std::endl;
}
  • person.h 文件
#pragma once	// 只要在头文件的最开始加入这条预处理指令,就能够保证头文件只被编译一次,防止头文件被重复引用template<class T1, class T2>
class Person
{
public:Person(T1 name, T2 age);void showPerson();T1 m_Name;T2 m_Age;
};

类模板与友元

#include <iostream>
#include <string>
using namespace std;// 总结:
// 1. 全局函数,如果在类外实现的话,比较简单;如果在类外实现的话,比较复杂,需要提前让编译器知道全局函数的存在
// 2. 建议使用类内实现的方式,简单易懂// 提前让编译器知道Person类存在(才能实现全局函数,内类声明,类外实现)
template <class T1, class T2>
class Person;// 全局函数,内类声明,类外实现(这个函数模板实现必须要在类实现之前)
template <class T1, class T2>
void printPerson2(Person<T1, T2> p)
{cout << "姓名:" << p.m_Name << " 年龄:" << p.m_Age << endl;
}template <class T1, class T2>
class Person
{// 全局函数,类内实现friend void printPerson(Person<T1, T2> p){cout << "姓名:" << p.m_Name << " 年龄:" << p.m_Age << endl;}// 全局函数,类内声明,类外实现// 因为类型不一样(实现是函数模板,而声明是函数),所以需要加上空模板参数列表// 让它统一类型才不会报错,最终是(实现是函数模板,声明也是函数模板)friend void printPerson2<>(Person<T1, T2> p);public:Person(T1 name, T2 age) :m_Name(name), m_Age(age){cout << "成功构造了一个对象" << endl;}private:T1 m_Name;T2 m_Age;
};void test()
{// 全局函数,类内实现Person<string, int> p1("Jack", 29);printPerson(p1);// 全局函数,类外实现Person<string, int> p2("Tom", 30);printPerson2(p2);
}int main()
{test();
}

模板案例

  • main.cpp 文件
#include <iostream>
#include <string>
#include "MyArray.hpp"
using namespace std;// 基本数据类型-数组测试
void test1()
{// 创建一个int类型,数组长度为10的数组对象 arr1MyArray<int> arr1(10);			// 调用构造函数MyArray<int> arr2 = arr1;		// 调用拷贝构造函数MyArray<int> arr3(20);arr3 = arr1;					// 赋值运算符重构bool ret;for (int i = 0; i < arr3.getCapacity(); i++){ret = arr3.append(100 - i);		// 尾追加cout << ret << endl;}cout << "----------" << endl;arr3.pop();						// 尾删除cout << arr3[9] << endl;		// []运算符重载		输出结果:91arr3[9] = 666;cout << arr3[9] << endl;		// []运算符重载		输出结果:666
}// 自定义数据类型-数组测试
class Person
{
public:Person() {}Person(string name, int age){this->m_Name = name;this->m_Age = age;}string m_Name;int m_Age;
};void test2()
{MyArray<Person> arr(3);Person p1("Jack", 25);Person p2("Tom", 28);Person p3("Jim", 29);// 将数据插入到数组中arr.append(p1);arr.append(p2);arr.append(p3);// 打印数组for (int i = 0; i < arr.getCapacity(); i++){cout << "姓名:" << arr[i].m_Name << "\t年龄:" << arr[i].m_Age << endl;}
}int main()
{// 基本数据类型-数组测试test1();cout << "*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*" << endl;// 自定义数据类型-数组测试test2();system("pause");return 0;
}/*运行结果:1111111111----------91666*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*姓名:Jack      年龄:25姓名:Tom       年龄:28姓名:Jim       年龄:29
*/
  • MyArray.hpp 文件
// 实现一个通用的数组类
#pragma once
#include <iostream>
#include <string>template <class T>
class MyArray
{
private:T* pAddress;		// 指针指向堆区开辟的真实数组int m_Capacity;		// 数组容量int m_Size;			// 数组元素个数public:// 构造函数MyArray(int capacity){this->m_Capacity = capacity;this->m_Size = 0;this->pAddress = new T[this->m_Capacity];}// 析构函数~MyArray(){if (this->pAddress != NULL){delete[] this->pAddress;this->pAddress = NULL;}}// 拷贝构造/*针对以下问题:MyArray<int> arr1(8);MyArray<int> arr2 = arr1;*/MyArray(const MyArray& arr){this->m_Capacity = arr.m_Capacity;this->m_Size = arr.m_Size;// 深拷贝this->pAddress = new T[arr.m_Capacity];for (int i = 0; i < arr.m_Size; i++){this->pAddress[i] = arr.pAddress[i];}}// 赋值运算符重构/*针对以下问题:MyArray<int> arr1(11), arr2(8), arr3(13);arr1 = arr2 = arr3;*/MyArray& operator=(const MyArray& arr){// 先判断原来堆区是否有数据,如果有先释放if (this->pAddress != NULL){delete[] this->pAddress;this->pAddress = NULL;this->m_Capacity = 0;this->m_Size = 0;}this->m_Capacity = arr.m_Capacity;this->m_Size = arr.m_Size;// 深拷贝this->pAddress = new T[arr.m_Capacity];for (int i = 0; i < arr.m_Size; i++){this->pAddress[i] = arr.pAddress[i];}return *this;}// 尾追加/*针对以下问题:MyArray<int> arr1(8);arr1.append()*/bool append(const T& value){// 判断是否已经满了,如果满了,无法插入if (this->m_Size == this->m_Capacity)	return false;// 插入操作this->pAddress[m_Size] = value;m_Size++;return true;}// 尾删除/*针对以下问题:MyArray<int> arr1(8);arr1.pop()*/void pop(){// 判断数组是否为空if (this->m_Size == 0)	return;// 删除操作m_Size--;}// []运算符重构/*针对以下问题:通过下标的方式"访问"数组中的元素 cout << a[0] << endl;通过下标的方式"修改"数组中的元素 a[0] = 99;*/T& operator[](int index){return this->pAddress[index];}// 获取元素个数int getSize(){return this->m_Size;}// 获取数组容量int getCapacity(){return this->m_Capacity;}
};

http://www.mrgr.cn/p/72152311

相关文章

云计算时代:SFP、SFP+、SFP28、QSFP+和QSFP28光纤模块详解

随着数据中心的快速发展和云计算的广泛应用&#xff0c;高速、高效率的光纤网络传输成为关键需求。在众多光纤模块中&#xff0c;SFP、SFP、SFP28、QSFP和QSFP28是最常见的几种类型。本文将为您详细解析这几种光纤模块之间的区别&#xff0c;帮助您更好地了解和选择适合自己需求…

安装crossover游戏提示容量不足怎么办 如何把游戏放到外置硬盘里 Mac电脑清理磁盘空间不足

CrossOver作为一款允许用户在非原生操作系统上运行游戏和应用程序的软件&#xff0c;为不同平台的用户提供了极大的便利。然而&#xff0c;随着游戏文件大小的不断增加&#xff0c;内置硬盘的容量往往无法满足安装需求。幸运的是&#xff0c;通过一些简单的步骤&#xff0c;我们…

【深度学习】神经网络中的激活函数:释放非线性的力量

神经网络中的激活函数&#xff1a;释放非线性的力量 一、激活函数的原理与作用二、激活函数的实例与代码实现三、激活函数的热点应用四、结语 在人工智能的浪潮中&#xff0c;人工神经网络&#xff08;ANN&#xff09;以其强大的学习和拟合能力&#xff0c;日益成为解决复杂问题…

pytest-xdist:远程多主机 - 分布式运行自动化测试

简介&#xff1a;pytest-xdist插件使用新的测试执行模式扩展了pytest&#xff0c;最常用的是在多个CPU之间分发测试以加快测试执行&#xff0c;即 pytest -n auto同时也是一个非常优秀的分布式测试插件&#xff0c;分别支持ssh和socket两种方式实现master和worker的远程通讯。…

Pytorch 之torch.nn初探 卷积--Convolution Layers

任务描述 本关任务&#xff1a; 本关提供了一个Variable 类型的变量input&#xff0c;按照要求创建一 Conv1d变量conv&#xff0c;对input应用卷积操作并赋值给变量 output&#xff0c;并输出output 的大小。 相关知识 卷积的本质就是用卷积核的参数来提取原始数据的特征&a…

ssm智能停车场管理系统

视频演示效果: SSMvue智能停车场 摘 要 本论文主要论述了如何使用JAVA语言开发一个智能停车场管理系统&#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述智能停车…

Bert语言大模型基础

一、Bert整体模型架构 基础架构是transformer的encoder部分&#xff0c;bert使用多个encoder堆叠在一起。 主要分为三个部分&#xff1a;1、输入部分 2、注意力机制 3、前馈神经网络 bertbase使用12层encoder堆叠在一起&#xff0c;6个encoder堆叠在一起组成编码端&#xf…

在Linux系统内搭建DNS本地服务器

文章目录 Linux的本地DNS服务一、什么是DNS1.1、域名1.2、DNS服务器、DNS客户端和DNS中继1.3、DNS域名解析 二、搭建DNS服务2.1、正反向解析2.1.1.安装bind软件包2.1.2.修改主配置文件2.1.3.修改区域配置文件2.1.4.配置区域数据文件2.1.5.启动服务、关闭防火墙2.1.6.本地解析测…

vue echarts 柱状图 堆叠柱状图

echarts堆叠柱状图&#xff08;效果图在文章末尾&#xff09; 1、默认只显示 月度的 数据&#xff0c;手动点击 legend 季度的 数据才会显示&#xff1b; 2、监听左侧菜单栏的宽度变化&#xff0c;图表宽度自适应展示 <template><div><div id"barChart&q…

RabbitMQ工作模式(5) - 主题模式

概念 主题模式&#xff08;Topic Exchange&#xff09;是 RabbitMQ 中一种灵活且强大的消息传递模式&#xff0c;它允许生产者根据消息的特定属性将消息发送到一个交换机&#xff0c;并且消费者可以根据自己的需求来接收感兴趣的消息。主题交换机根据消息的路由键和绑定队列的路…

Java 提取HTML文件中的文本内容

从 HTML 文件中提取文本内容是数据抓取中的一个常见任务&#xff0c;你可以将提取的文本信息用于编制报告、进行数据分析或其他处理。本文分享如何使用免费 Java API 从HTML 文件中提取文本内容。 安装免费Java库&#xff1a; 要通过Java提取HTML文本&#xff0c;需要用到Free…

增加PyQt5界面的交通流量预测(模型为CNN_GRU,CNN_BiGRU_ATTENTION,LSTM,Python代码)

1.效果视频&#xff1a;增加PyQt5界面的交通流量预测&#xff08;模型为CNN_GRU&#xff0c;CNN_BiGRU_ATTENTION&#xff0c;LSTM&#xff09;_哔哩哔哩_bilibili&#xff09; 2.三个模型和数据集的介绍 交通流量预测(python代码&#xff0c;压缩包中带有数据&#xff0c;CN…

plsql 新建sql窗口 初始化慢的问题

问题描述&#xff1a; 新建sql窗口当sql语句多的情况下初始化很慢。 解决方法&#xff1a; 采用导入表的方式。 具体方式 工具->导入表->sql插入。 使用命令窗口 导入文件&#xff0c;然后点击导入按钮。

2024蓝桥杯嵌入式模板代码详解

文章目录 一、STM32CubeMx配置二、LED模板代码三、LCD模板代码 一、STM32CubeMx配置 打开STM32CubeMx&#xff0c;选择【File】->【New Project】&#xff0c;进入芯片选择界面&#xff0c;搜索到蓝桥杯官方的芯片型号&#xff0c;并点击收藏&#xff0c;下次直接点击收藏就…

debian gnome-desktop GUI(图形用户界面)系统

目录 &#x1f31e;更新 &#x1f3a8;安装 &#x1f34e;分配 &#x1f6cb;️重启 &#x1f511;通过VNC连接 debian gnome-desktop &#x1f31e;更新 sudo apt update sudo apt -y upgrade &#x1f3a8;安装 sudo apt -y install task-gnome-desktop 这个过程比…

sheng的学习笔记-AI-支持向量机(SVM)

目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 目录 什么是向量机 SVM算法原理 SVM基本模型 SVM对偶问题 什么是对偶问题&#xff1a; 为什么使用对偶问题 拉格朗日定理 拉格朗日乘子法 对偶问题算法 非线性SVM算法原理 核函数 常用核函数 软间隔与正则化 软…

华为NPU开发流程点滴

华为NPU开发流程点滴 NPU/CPU集成操作流程图介绍了App使用HUAWEI HiAI DDK的集成流程。IR在线模型构建 IR在线模型构建通过IR单算子根据原始模型中的关系级联,配置权重数据,构建IR模型网络。 离线模型转换 离线模型转换需要将Caffe、TensorFlow、ONNX、MindSpore模型转换为HU…

Spring 注解开发详解

1. 注解驱动入门案例介绍 1.1 需求描述 1.需求&#xff1a;实现保存一条数据到数据库。 2.表结构&#xff1a;create table account(id int primary key auto_increment,name varchar(50),money double(7,2)); 3.要求&#xff1a;使用spring框架中的JdbcTemplate和DriverMana…

CISCN 2023 WEB

CISCN 2023 WEB unzip 前置知识unzip是linux系统下的一个解压缩命令:unzip指令解压,将压缩文件test.zip在指定目录/tmp(当前)下解压缩,如果已有相同的文件存在,要求unzip命令覆盖原先的文件。软连接:类似于Windows的快捷方式,但是它可以直接操作软连接指向的对象,而Wi…

【Docker】Docker的网络与资源控制

Docker网络实现原理 Docker使用Linux桥接&#xff0c;在宿主机虚拟一个Docker容器网桥(docker0)&#xff0c;Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址&#xff0c;称为Container-IP&#xff0c;同时Docker网桥是每个容器的默认网关。因为在同一宿主机内…