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 != 
上一篇:实现 vue&react 混合开发项目步骤-微前端-二、简单案例


下一篇:docker 启动时报错