自学内容网 自学内容网

c++补充

构造函数、析构函数

#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、300

Person 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;// 输出:2
cout << myint << endl;// 输出:2

cout << myint++ << endl;// 输出:2
cout << 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;// 输出结果:10

Person p2(20);
cout << "p2的年龄为:" << *p2.age << endl;// 输出结果:20

Person p3(30);
cout << "p3的年龄为:" << *p3.age << endl;// 输出结果:30

// 这不是拷贝构造函数,拷贝构造函数也是一种构造函数
// 这里是赋值语句,对象的赋值,编译器默认的行为是:将某对象的所有属性复制一份到另一个对象里面
// 因为默认行为的直接复制,对于需要浅拷贝的内容没什么影响,但是对于需要深拷贝的内容影响很大
// 为了避免恶劣影响,我们需要重载赋值运算符
p3 = p2 = p1;
cout << "修改后的p2的年龄为:" << *p2.age << endl;// 输出结果:10
cout << "修改后的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;// 输出结果:1

Person 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的数组对象 arr1
MyArray<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;// []运算符重载输出结果:91
arr3[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;
}

/*
运行结果:
1
1
1
1
1
1
1
1
1
1
----------
91
666
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
姓名: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;
}
};

原文地址:https://blog.csdn.net/code_stream/article/details/138005085

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!