C++核心编程

1、程序的内存模型

/*

代码区 :
	放二进制编译好的代码, 生成exe的可执行程序
	存放cpu执行的机器指令
	特点:共享,只读



全局区:
	全局变量,字符串常量,其他常量, 静态变量
	当进程结束时才会死亡


栈区:由编译器自动分配,管理函数的生成与死亡


堆区:由操作者进行

*/

#include <iostream>
using namespace std;

int main() {

	return 0;
}

2、栈区

#include<iostream>
using namespace std;

// 不要返回栈区的地址, 因为栈区的局部变量会由编译器自动释放

// 在这里保留了局部变量

int* func() {
	int a = 10;
	return &a;
}

int main() {
	int* p = func();
	cout << *p << endl;
	cout << *p << endl;
	
	return 0;
}

3、堆区

#include<iostream>
using namespace std;

int* func() {
	// 利用 new 将数据开辟到堆区
	// 指针本质也是一个局部变量
	// 用局部变量指针来储存全局变量的地址
	int* p = new int(10);
	return p;
}

int main() {
	// 在这里的堆区创建了一个指针来储存来自栈区返回的一个地址
	int* p = func();
	cout << *p << endl;

	return 0;
}

4、new 的基本用法

#include<iostream>
using namespace std;


int* func() {

	// 在堆区创建一个数据
	// new 返回的是该数据的指针

	int* p = new int(10);

	return p;
}

void test01() {

	int* p = func();
	cout << *p << endl;
	// 堆区的数据由程序员管理释放
	// 如果想释放,用堆区的关键字 delete
	// delete 的对象是一个指针
	delete p;
	// 内存已经释放,再操作为非法操作
}


// 2 在堆区用new开辟一个数组

void test02() {

	// 数组中有10个元素
	int* arr = new int[10];

	for (int i = 0; i < 10; i++) {
		arr[i] = i;
	}
	for (int i = 0; i < 10; i++) {
		cout << arr[i] << "array" << endl;
	}
	// 释放数组
	// 释放数组的是一个中括号,否则释放第一个元素
	delete[] arr;
}

int main() {

	test01();
	// 1 new的基本语法
	test02();


	return 0;
}

5、引用的基本语法

#include <iostream>
using namespace std;

// 实质,给变量起别名,使不同的变量操作相同的内存空间

int main() {

	int a = 10;

	int& b = a;

	b = 20;

	cout << "a=" << a;


	return 0;
}

6、引用的注意事项

#include <iostream>
using namespace std;




int main() {
	int a = 10;
	// 引用必须要初始化
	int& b = a;
	// 引用一旦初始化后就不可以更改
	int c = 20;

	b = c; // 赋值操作而不是更改引用


	return 0;
}

7、引用做函数参数

#include <iostream>
using namespace std;


// 交换函数


// 值传递, 形参不修饰实参
void swap1(int a, int b) {
	int temp = a;
	a = b;
	b = temp;
}

// 地址传递, 形参修饰实参
void swap2(int* a, int* b) {
	int temp = *a;
	*a = *b;
	*b = temp;
}


// 引用传递, 形参修饰实参, 别名和原名一样的
void swap3(int& a, int& b) {
	int temp = a;
	a = b;
	b = temp;
}



int main() {
	int a = 10;
	int b = 20;

	swap1(a, b);
	cout << "swap1 " << a << " and " << b << endl;
	swap2(&a, &b);
	cout << "swap2 " << a << " and " << b << endl;
	swap3(a, b);
	cout << "swap3 " << a << " and " << b << endl;
	return 0;
}

8、引用做函数的返回值

#include <iostream>
using namespace std;

// 不要返回局部变量的引用
int& test01() {
	
	int a = 10;

	return a;
}


// 函数的调用可以作为左值
int& test02() {

	// 静态变量存放在全局区
	static int a = 10;

	return a;
}


int main() {
	int& b = test01();

	// 第一次正确是应为编译器做了保留, 我这里没有保留
	cout << "ref1 = " << b << endl;

	int& c = test02();
	cout << "ref2 = " << c << endl;

	c = 100;
	cout << "ref2 = " << test02() << endl;

	// 作为左值, 函数的每次调用返回的引用,都是相同的内存地址, 也就是全局变量的相同的指针
	test02() = 1000;
	cout << "ref2 = " << c << endl;

	return 0;
}

9、引用的本质

#include <iostream>
using namespace std;

// 引用的本质就是指针常量

// int& a = a; ===> int* const a = &a;

int main() {

	return 0;
}

10、常量引用

#include <iostream>
using namespace std;


void showVal(const int& a) {

	cout << "val = " << a << endl;
}



 // 用来修饰常量,使其不可以被修改
int main() {

	// 编译器会自动创建一个值为10的内存空间,并且会自动生成一个原名,
	// 因此我们只能使用 引用的别名
	// 同时引用的值不能被修改
	const int& a = 10;


	// 主要用来修饰形参, 防止误操作

	int a = 100;

	return 0;
}

11、函数的默认参数

#include <iostream>
using namespace std;

int calculate(int a = 10, int b = 20) {

	return a + b;
}

// 当声明有了默认参数时, 函数的实现就不能有默认参数
// 函数的声明和实现只能有一个存在默认参数
// 函数的声明
int func(int a = 10, int b = 10);

int main() {

	int a = calculate();

	cout << a << endl;

	return 0;
}

// 函数的实现
int func(int a, int b) {
	return a + b;
}

12、函数的占位参数

#include <iostream>
using namespace std;

// 放一个书包来占位置
// 目前阶段的占位参数用不到
void func(int a, int) {
	cout << "this is " << a << endl;
}

// 占位参数可以有默认参数 func(int a = 10, int = 20)

int main() {

	func(10, 10);

	return 0;
}

13、函数重载的基本用法

#include <iostream>
using namespace std;


// 条件
// 必须在同一个作用域下
// 函数名称相同
// 函数的参数类型,个数,顺序不同

void func() {

	cout << "func ----> " << endl;
}

void func(int a) {

	cout << "func a ----> " << endl;
}

int main() {
	func();
	func(1);

	return 0;
}

14、函数重载的注意事项

#include <iostream>
using namespace std;


// 引用
void func(int& a) {
	cout << "func no const" << endl;
}

void func(const int& a) {
	cout << "func const" << endl;
}

// 函数重载遇见默认参数

void func1(int a, int b = 10) {
	cout << "func default" << endl;
}
void func1(int a) {
	cout << "func no default" << endl;
}

int main() {

	int a = 10;
	// 引用
	func(a);
	func(20);
	// 默认参数
	// 传一个参数时会报错,两个不会报错
	func1(10, 10);
	return 0;
}

15、类和对象封装属性和行为

#include <iostream>
using namespace std;


// design a circle to calc the arc
const double PI = 3.14;

class Circle {
	//访问权限
public:
	// 属性
	int r;

	//行为
	double calcArc(){
		return 2 * PI * r;
	};
};


int main() {
	// 实例化对象
	Circle c1;
	c1.r = 10;
	cout << "circle len = " << c1.calcArc() << endl;

	return 0;
}

16、设计学生类

#include <iostream>
using namespace std;


class Student {
public:
	string name;
	int id;

	void set_name(string name_) {
		name = name_;
	}

	void show_id_name() {
		cout << "name:" << name << "\tid:" << id << endl;
	}
};


int main() {

	Student student;

	student.name = "alex";
	student.id = 202031080136;
	student.show_id_name();

	return 0;
}

17、封装访问权限

#include <iostream>
using namespace std;

// public ----> 类里类外都可以访问
// private ---->  只有类里可以访问 (私有成员变量) ----> 继承的子类不可以访问
// protected ----> 只有类里可以访问 (私有成员变量) ----> 继承的子类可以访问

class Person {

public:
	string name;

	void set_name(){
		name = "alex";
		Car = "car";
		password = 34121234;
	};

protected:
	string Car;

private:
	int password;
};


int main() {


	Person person;
	Person* p = &person;

	cout << p->name << endl;

	return 0;
}

18、class与struct的区别

#include <iostream>
using namespace std;

// struct 默认的权限为 public
// class 默认的权限为私有

int main() {

	return 0;
}

19、成员属性的私有化

#include <iostream>
using namespace std;

class Person {

public:
	void setName(string name_){
		name = name_;
	};
	string getName() {
		return name;
	};

	int getAge() {
		age = 10;
		return age;
	}

	void setLover(string lover_) {
		lover = lover_;
	}

private:
	string name;

	int age;

	string lover;
};

int main() {

	Person person;
	person.setName("alex");

	cout << "name : " << person.getName() << endl;

	cout << "age: " << person.getAge() << endl;

	return 0;
}

20、实例:立方体类的设计

#include <iostream>
using namespace std;

class Cube {
public:
	void setMeasure(int width, int height, int len) {
		_width = width;
		_height = height;
		_len = len;
	}
	int* getMeasure() {
		return arr;
	}
	int calcArea() {
		return (_width * _height + _height * _len + _len * _width) * 2;
	}


private:
	int _width;
	int _len;
	int _height;
	int arr[3] = { _width, _height, _len };
};


int main() {
	
	Cube cube;
	cube.setMeasure(10, 10, 10);
	int* p = cube.getMeasure();
	for (int i = 0; i < 3; i++) {
		cout << i << "-----" << p[i] << endl;
	}
	cout << "cube area : " << cube.calcArea() << endl;

	return 0;
}

21、示例:点和圆的位置关系

#include <iostream>
#include<math.h>
using namespace std;

struct Point {
	int centerX;
	int centerY;

	void setCenter(int x, int y){
		centerX = x;
		centerY = y;
	};
};




class Circle {

public:
	int setR(int r) {
		radius = r;
	}
	int getR() {
		return radius;
	}
	void setCenter(int x, int y) {
		point.setCenter(x, y);
	}
	Point getCenter() {
		return point;
	}
	// 判断点和圆的关系
	void isIncicle(Point point_) {
		int distance = sqrt(pow((point.centerX - point_.centerX), 2) + pow((point.centerY - point_.centerY), 2));
		if (distance == radius) {
			cout << "on circle" << endl;
		}
		else if (distance > radius) {
			cout << "out circle" << endl;
		}
		else if (distance < radius) {
			cout << "in circle" << endl;
		}
		
	}

private:
	int radius = 10;
	Point point;
};



int main() {

	Circle circle;
	circle.setCenter(10, 10);

	Point point = { 30, 10 };

	circle.isIncicle(point);

	return 0;
}

22、构造函数和析构函数

#include <iostream>
using namespace std;

// 构造函数语法
// 析构函数语法

// 不写的话会默认调用空的构造和析构

// 对象的初始化和清理
class Person {
public:
	Person();
	~Person();

private:
};

// 构造函数, 可以发生重载
Person::Person() {
	cout << "构造函数的调用" << endl;
}
// 析构函数, 对象清理的时候调用
Person::~Person() {
	cout << "析构函数的调用" << endl;
}


void test01() {
	// 栈区上的数据,调用完后会释放
	Person person;
}

int main() {
	        
	test01();
	return 0;
}

23、函数的分类和调用

#include <iostream>
using namespace std;

// 构造函数的分类以及调用

class Person {
public:
	int age;
	// 普通构造函数
	Person();
	Person(int a);

	// 拷贝构造函数
	Person(const Person &p){
		// 将传入的人身上所有的2属性都传递给这里
		// 将传入的属性
		cout << "拷贝函数的构造的调用" << endl;
		age = p.age;
	};

	~Person();

private:
};

Person::Person() {
	cout << "无参数构造函数的调用" << endl;
}

Person::Person(int a) {
	age = a;
	cout << "有参数构造函数的调用" << endl;
}

Person::~Person() {
	cout << "析构函数的调用" << endl;
}

// 调用
void test01() {
	// 默认构造函数地调用
	// 调用默认构造时最好不要加括号!!!
	Person p1;
	// 因为编译器会默认为函数的声明, 不会创建对象
	Person p2(10);
	cout << "p2 -> age :" << p2.age << endl;
	// 拷贝构造
	Person p3(p2);
	cout << "p3 -> age :" << p3.age << endl;

	// 显示法构造
	Person p11;
	Person p12 = Person(10);
	Person p13 = Person(p2);
	// Person(10) : 匿名对象

	// 不要利用拷贝构造函数来匿名调用调用
	//Person(p3), 否者会认为对象的声明

	// 隐式转化法
	Person p4 = 10;
	// 拷贝构造
	Person p5 = p4;
}
                                                                                                                        
int main() {
	test01();
	return 0;
}

24、拷贝构造函数的调用时机

#include <iostream>
using namespace std;

class Person {
public:
	Person(int age);
	Person(const Person& p);
	~Person();
	int age;

private:
};

Person::Person(int age_) {
	age = age_;
	cout << "__init__" << endl;
}

Person::Person(const Person& p){
	age = p.age;
	cout << "__init__ copy" << endl;
};

Person::~Person() {
	cout << "__del__" << endl;
}

// 声明
void doWork(Person p);

// 拷贝函数的构造时机
// 使用一个已经创建完对象再来创建另一个对象
void test01() {
	Person p1(10);
	Person p2(p1);
	cout << "p1:" << p1.age << "\tp2:" << p2.age << endl;

}

// 值传递方式给函数参数传值
// 这里会拷贝一个变量p,也就是会再次实例化一个对象
// 使传入的实参p 和 形参p 表面相同, 实际指向的地址是不同的

void test02() {
	Person p1(10);
	// callback
	doWork(p1);
};
void doWork(Person p) {
	
}

// 值方式返回局部对象
Person doWork02() {
	Person p1(10);

	cout << (int*)&p1 << endl;
	// 返回的是一个拷贝对象, 地址和局部对象的地址不相同

	return p1;
}
void test03() {
	Person p = doWork02();
	cout << (int*)&p << endl;
}

int main() {

	//test01();
	//test02();
	test03();

	return 0;
}

25、构造函数的调用规则

#include <iostream>
using namespace std;

// 默认会提供构造函数, 拷贝函数, 析构函数

int main() {

	return 0;
}

26、深拷贝与浅拷贝

#include <iostream>
using namespace std;

// 默认会提供构造函数, 拷贝函数, 析构函数

int main() {

	return 0;
}

27、初始化列表

#include <iostream>
using namespace std;

class Person {
public:
	int a;
	int b;
	int c;
	Person(int x, int y, int z) {
		a = x;
		b = y;
		c = z;
	}
};

// 初始化值
class Person1 {
public:
	int a;
	int b;
	/*
	Person1() : a(10), b(20) {

	}
	*/
	Person1(int a, int b) : a(a), b(b) {

	}
};


int main() {

	Person p(1, 2, 3);
	cout << "a:" << p.a << "b:" << p.b << "c:" << p.c << endl;

	Person1 p1(10, 20);
	cout << "a:" << p1.a << "b:" << p1.b << endl;

	return 0;
}

28、类对象作为类成员

#include <iostream>
using namespace std;

class Person {
public:
	int a;
	int b;
	int c;
	Person(int x, int y, int z) {
		a = x;
		b = y;
		c = z;
	}
};

// 初始化值
class Person1 {
public:
	int a;
	int b;
	/*
	Person1() : a(10), b(20) {

	}
	*/
	Person1(int a, int b) : a(a), b(b) {

	}
};


int main() {

	Person p(1, 2, 3);
	cout << "a:" << p.a << "b:" << p.b << "c:" << p.c << endl;

	Person1 p1(10, 20);
	cout << "a:" << p1.a << "b:" << p1.b << endl;

	return 0;
}

29、静态成员函数

#include <iostream>
using namespace std;

// 静态成员函数
// 所有对象共享一个函数
// 静态成员函数只能访问静态成员变量



class Person {
public:
	// 非静态成员变量
	int b;
	// 静态成员变量
	static int a;
	// 静态成员函数
	static void func() {
		// 静态成员函数可以访问静态成员变量
		a = 100; // 静态成员所有类都共享有一份
		// b = 200; 错误, 无法区分到底是哪一个对象的
		cout << "call func" << endl;
	}

private:
	static void func2() {
		cout << "private static func" << endl;
	}
};

// 在类外初始化变量
int Person::a = 0;

void test01() {
	// 通过对象进行访问
	Person p;
	p.func();
	// 通过类名进行访问
	Person::func();
}


int main() {
	test01();
	return 0;
}

30、成员变量和成员函数分开储存

#include <iostream>
using namespace std;

// 成员变量 成员函数 分开储存



class Person {
	// 非静态成员函数与成员变量分开存储,也就是结果内存空间始终为1字节
	// 不属于类的对象上
	void func() {

	}
	// 不属于类的对象上
	static void func1() {

	}
};

void test01() {
	Person p;
	// c++ 编译器会给每一个空对象分配一个1字节的内存空间
	cout << "size of empty p = " << sizeof(p) << " bit" << endl;

}


class Person2 {
public:
	int a;
};

void test02() {
	Person2 p2;
	// c++ 编译器会给每一个非空对象分配一个4(int)字节的内存空间
	cout << "size of non empty p = " << sizeof(p2) << " bit" << endl;
}

class Person3 {
public:
	int a;
	static int b;
};
int Person3::b = 10;


void test03() {
	Person3 p3;
	// c++ 编译器会给每一个非空对象分配一个4(int)字节的内存空间, 静态变量不属于类的对象上,不占用空间
	cout << "size of non empty p = " << sizeof(p3) << " bit" << endl;
}


int main() {

	// test01();

	// test02();

	//test03();

	return 0;
}

31、this指针的用途

#include <iostream>
using namespace std;

class Person {
public:
	int age;
	// 解决名称冲突
	Person(int age) {
		// this 指向被调用成员函数所属的对象, this指向p1;
		this->age = age;
	}
	// 返回对象本身
	Person& personAddAge(Person p) {
		this->age += p.age;
		return *this;
	}
};


void test01() {

	Person p(10);
	cout << "p1 -> age : " << p.age << endl;

}

void test02() {
	Person p1(10);
	Person p2(10);
	// 链式编程思想
	p2.personAddAge(p1).personAddAge(p1).personAddAge(p1);
	cout << "p2 age->" << p2.age << endl;
}

int main() {
	//test01();
	test02();
	return 0;
}

32、空指针访问成员函数

#include <iostream>
using namespace std;

// 空指针调用成员函数

class Person {
public:
	int m_age;
	void showPersonAge() {
		if (this == NULL) {
			return;
		}
		cout << "age = " << this->m_age << endl;
	}
	void showClassName() {
		cout << " this is a class" << endl;
	}
};

void test01() {
	Person* p = NULL;
	// 不会报错
	p->showClassName();
	// p 并没有创建一个实例,传入的指针为空, this 对应的 p 为空
	p->showPersonAge();
}

int main() {
	test01();
	return 0;
}

33、const修饰成员函数

#include <iostream>
using namespace std;


class Person {
public:
	int m_a;
	// 即使在常函数中也可以修改这个值, 加入限制 mutable
	mutable int m_b;
	// 常函数
	void showPerson() const
	{
		// m_a = 100; 不能修改 this—>m_a
		// this 指针常量, 指针是不可以修改的; this->NULL 错误, Person* const this;
		// this 指向的值一般是可以修改的
		// same to =====> const Person* const this; fist const limit the variable
	}
};

void test01() {
	Person p;
	p.showPerson();
}

// 常对象
void test02() {
	// 修饰的属性不允许修改
	// 可以添加 mutable 使成为可以修改的对象
	const Person p;
	p.m_b = 100;
	// 常对象只能调用常函数
	p.showPerson();
	// 普通成员函数可能会修改属性与之冲突
}

int main() {
	test01();
	return 0;
}

34、友元-常函数做友元

#include <iostream>
using namespace std;


// 全局函数做友元

class Buliding {
public:
	Buliding() {
		mSittingRoom = "客厅";
		mBedRoom = "卧室";
	}
	string mSittingRoom;

private:
	// 将全局函数的声明写道这里
	friend void goodGay(Buliding* buliding);
	string mBedRoom;
};

// gloable function
// 全局函数 
void goodGay(Buliding* buliding) {
	cout << "好基友的全局函数正在访问 : " << buliding->mSittingRoom << endl;
	cout << "好基友的全局函数正在访问 : " << buliding->mBedRoom << endl;
}

void test01() {
	Buliding building;
	goodGay(&building);
}


int main() {
	test01();
	return 0;
}

35、友元类

#include <iostream>
using namespace std;

class Buliding {
public:
	Buliding();
	string mSittingRoom;

private:
	string mBedRoom;
	// 写在这里-------->
	friend class GoodGay;
};

Buliding::Buliding() {
		mSittingRoom = "客厅";
		mBedRoom = "卧室";
}

class GoodGay {
public:
	GoodGay();
	Buliding* building;
	void visit();
};

GoodGay::GoodGay() {
	// 创建建筑物对象
	building = new Buliding;
}
void GoodGay::visit() {
	cout << "好基友的类正在访问: " << building->mSittingRoom << endl;
	cout << "好基友的类正在访问: " << building->mBedRoom << endl;
}

int main() {

	GoodGay goodGay;
	goodGay.visit();


	return 0;
}

36、成员函数做友元

#include <iostream>
using namespace std;

class GoodGay;
class Building;

// GoodGay 一定要先放在 Building 前面, Building创建朋友时,一定要先存在 visit()在类GoodGay中
class GoodGay {
public:
	GoodGay();
	Building* building;
	void visit1(); // 让visit1 可以访问building中的私有成员
	void visit2(); // 让visit2 可以访问building中的私有成员

private:
};

class Building {

	friend void GoodGay::visit1();

public:
	string mSettingRoom;
	Building();

private:
	
	string mBadRoom;
};
Building::Building() {
	mSettingRoom = "客厅";
	mBadRoom = "卧室";
}

GoodGay::GoodGay() {
	building = new Building;
}                        
void GoodGay::visit1() {
	cout << "visit1正在访问:" << building->mSettingRoom << endl;
	cout << "visit1正在访问:" << building->mBadRoom << endl;
}

void GoodGay::visit2() {
	cout << "visit2正在访问:" << building->mSettingRoom << endl;
}

void test01() {
	GoodGay gg;
	gg.visit1();
	gg.visit2();
}

int main() {
	test01();
	return 0;
}

37、加号运算符重载

#include <iostream>
using namespace std;

// 加号运算符重载

class Person {
public:
	int a;
	int b;
	Person() {

	}
	Person(int a_, int b_) {
		a = a_;
		b = b_;
	}
	// 函数的内部进行重载
		Person operator+(Person& p) {
		Person temp;
		temp.a = this->a + p.a;
		temp.b = this->b + p.b;
		return temp;
	}

private:
};

// 函数外部的重载
/*
Person operator+(Person& p1, Person& p2) {
	Person temp;
	temp.a = p1.a + p2.a;
	temp.b = p1.b + p2.b;
	return temp;
}
*/


// 成员函数的重载


void test01() {

	Person p1(10, 10);
	Person p2(10, 10);
	Person p3 = p1 + p2;
	cout << p3.a << "  " << p3.b << endl;
}

int main() {
	test01();
	return 0;
}

38、左移运算符重载

#include <iostream>
using namespace std;


// 可以输出自定义的数据类型
class Person {
	friend ostream& operator<<(ostream& cou, Person& p);
	friend void test01();
	int a;
	int b;
};

// 本质 cout << p ---> operator<<(cout, p)
// cout 全局只能有一个, 不能出现两个不同的地址
// 返回值是为了添加链式语法
// 引用的本身是起别名, out 与 cout 指向的是同一个地址
ostream& operator<<(ostream& cou, Person& p) {
	cou << "m_a = " << p.a;
	return cou;
}

void test01() {
	Person p;
	p.a = 10;
	p.b = 10;
	cout << p << " added" << endl;
}


int main() {
	test01();
	return 0;
}

39、递增运算符重载

#include <iostream>
using namespace std;

class MyPlus {
	friend ostream& operator<<(ostream& cout, MyPlus& myplus);
	friend void test01();

public:
	MyPlus() {
		a = 0;
	}
	// ++ 前置重载
	MyPlus& operator++() {
		++a;
		return *this;
	}
	// 后置重载
	// 如果返回的是引用那么返回的是局部对象的引用,所以返回的是一个值
	MyPlus& operator++(int) {
		// 记录当时结果
		// MyPlus temp = *this;
		// 递增
		a++;
		// 将记录的结果返回
		return *this;
	}

private:
	int a;
};

ostream& operator<<(ostream& cout, MyPlus& myplus) {
	cout << myplus.a;
	return cout;
}


void test01() {
	MyPlus myplus;
	cout << ++(++myplus) << endl;
	myplus++;
	myplus++;
	cout << myplus++ << endl;																		
}

int main() {
	test01();
	return 0;
}

40、赋值运算符重载

#include <iostream>
using namespace std;

// 赋值运算符的重载

class Person {
public:
	int* age;
	Person(int age) {
		this->age = new int(age);
	};
	~Person() {
		if (age != NULL) {
			delete this->age;
		}
	}
	Person& operator=(Person& p) {
		// 默认 age = p.age
		// 将拷贝出来的这一份改变age指针的指向
		if (age != NULL) {
			delete age;
			age = NULL;
		}
		age = new int(*p.age);
		return *this;
	}
};

void test01() {
	Person p1(18);
	cout << "person1 age: " << *p1.age << endl;

	Person p2(20);
	Person p3(30);
	// 赋值操作, 浅拷贝,导致堆区的内存重复释放
	p2 = p1 = p3;

	cout << "person2 age: " << *p2.age << endl;
	
}

int main() {
	test01();
	return 0;
}

41、关系运算符重载

#include <iostream>
using namespace std;


class Person {
public:
	string name;
	int age;
	Person(string name_, int age_) : name(name_), age(age_) {

	}
	bool operator==(Person& p) {
		if (this->age == p.age && this->name == p.name) {
			return true;
		}
		else {
			return false;
		}
	}
};

void test01() {
	Person p1("tom", 18);
	Person p2("tom", 18);
	if (p1 == p2) {
		cout << "p1 == p2" << endl;
	}
	else {
		cout << "p1 != p2" << endl;
	}
}

int main() {
	test01();
	return 0;
}

42、函数调用运算符重载

#include <iostream>
using namespace std;

// 函数调用运算符重载


class Print {

public:
	// 重载函数调用运算符
	// python "__call__"
	void operator()(string test) {
		cout << test << endl;
	}
};

void print02(string s) {
	cout << s << endl;
}

void test01() {
	Print print;
	print("Hello World");
	print02("hello world2");

	// 匿名对象, 执行完后就释放内存空间
	Print()("lambda ");
}


int main() {
	test01();
	return 0;
}

43、继承的基本语法

#include <iostream>
using namespace std;


class Header {
public:
	void header() {
		cout << "public header" << endl;
	}
};

//  继承的写法
class Java : public Header {
public:
	void java() {
		cout << "java" << endl;
	}
};

void test01() {
	Header head;
	head.header();

	Java java;
	java.header();
	java.java();
}


int main() {
	test01();
	return 0;
}

44、继承方式

#include <iostream>
using namespace std;

// public继承, 保持父类中public和protected
// protected继承, 将父类中的public与protected全部变为子类中的protected
// private 继承, 将父类中的public与protected全部变为子类中的private

int main() {
	 
	return 0;
}

45、继承中的对象模型

#include <iostream>
using namespace std;

// 继承中的对象模型

class Base {
public:
	int a;

private:
	int b;

protected:
	int c;
};

class Son : public Base {
public:
	int d;
};

void test01() {
	Son son;
	// 父类中所有的属性都会被继承, 只是被编译器屏蔽了,因此访问不到
	cout << sizeof(son) << endl; // 16  bites
}

int main() {
	test01();
	return 0;
}

46、继承中的构造与析构的顺序

#include <iostream>
using namespace std;

class Father {
public:
	Father();
	~Father();

private:
};

Father::Father() {
	cout << "father __init__" << endl;
}

Father::~Father() {
	cout << "father __del__" << endl;
}

class Son: public Father {
public:
	Son();
	~Son();

private:
};

Son::Son() {
	cout << "son __init__" << endl;
}

Son::~Son() {
	cout << "son__del__" << endl;
}

int main() {
	Son son;
	return 0;
}

47、同名成员处理

#include <iostream>
using namespace std;

class Father {
public:
	int a = 10;
	void func() {
		cout << "father func" << endl;
	}
	void func(int) {
		cout << "refunc in father" << endl;
	}
};

class Son : public Father {
public:
	int a = 100;
	void func() {
		cout << "son func" << endl;
	}
};

int main() {
	Son son;
	// 访问儿子中的属性
	cout << son.a << endl;
	son.func();
	// 访问父亲中的属性
	cout << son.Father::a << endl;
	son.Father::func();
	// 访问父亲中的重构函数
	son.Father::func(3);

	return 0;
}

48、同名静态成员的处理

#include <iostream>
using namespace std;

class Base {
public:
	static int a;
	static void func() {
		cout << "father static func" << endl;
	}
	static int func(int a_, int b_) {
		int c = a_ + b_;
		return c;
	}
};

int Base::a = 10;


class Son : public Base{
public:
	static int a;

	static void func() {
		cout << "son static func" << endl;
	}
	
};

int Son::a = 100;

// 同名静态成员的属性
void test01() {
	Son s;
	// 通过对象进行访问
	cout << "a= " << s.a << endl;

	cout << "base a=" << s.Base::a << endl;

	// 通过类名进行访问
	// first :: -> 通过类名的方式访问, seconed :: -> 代表访问父类作用域下的属性
	cout << Son::Base::a << endl;
	cout << Son::a << endl;

	// 通过对象访问
	s.func();
	s.Base::func();

	// 通过类名的方式进行访问
	Son::func();
	Son::Base::func();
	cout << "sum from father static method: " << Son::Base::func(10, 15) << endl;
}

int main() {
	test01();
	return 0;
}

49、多继承语法

#include <iostream>
using namespace std;

class Base1 {
public:
	int a = 10;

};

class Base2 {
public:
	int a = 20;
};

class Son : public Base1, public Base2 {
public:
	int c = 30;
	int d = 40;
};

void test01() {
	Son son;
	cout << "sizeof son = : " << sizeof(son) << endl;
	// 当父类中出现同名的成员时需要添加作用域进行区分
	cout << "son -> base1 -> prop:a ->" << son.Base1::a << endl;
}

int main() {
	test01();
	return 0;
}

50、菱形继承or钻石继承

#include <iostream>
using namespace std;

class Animal {
public:
	int age;
};

// 利用虚继承,解决菱形继承的问题 --> virtual -> 最大的类叫做虚基类
// 此时的数据为共享数据
// vbptr : virtual base poninter --> 虚基类指针 -->vbtable: virtual base table --> 虚基类表格
// 第一个 vbptr + 8( 地址偏移量) = 第二个vbptr + 4(地址偏移量) ---> vbtable(储存age的表格)
// 虚继承的不是两个数据,而是继承的是两个指针,指向同一个地址

class Sheep: virtual public Animal {

};

class Cat : virtual public Animal {

};

class SheepCat : public Sheep, public Cat {

};

void test01() {
	SheepCat sc;
	sc.Sheep::age = 18;
	sc.Cat::age = 19;
	cout << "sheep age: " << sc.Sheep::age << endl;
	cout << "cat age: " << sc.Cat::age << endl;
	// 菱形继承导致数据有两份,导致资源浪费
	cout << "虚继承之后: " << sc.age << endl;
}

int main() {
	test01();
	return 0;
}

51、多态的基本语法

#include <iostream>
using namespace std;



class Animal {
public:
	// ------------ 动态多态  -------------- 地址的晚绑定:运行阶段确定函数 ------------
	// 加了 virtual 后, 会优先从继承的类中寻找函数, 找不到再从父类中找
	// 这个就是地址的晚绑定
	// 否则会优先从父类中寻找,这个就是地址的早绑定
	virtual void speak() {
		cout << "animal speak " << endl;
	}
};

class Cat : public Animal{
public:
	void speak() {
		cout << "cat speak " << endl;
	}
};


// 执行说话的函数
// Animla & animal = cat;
// 运行相互引用 ---》 animal中的speak函数
// 地址在编译阶段就确定了函数的地址
void doSpeak(Animal& animal) {
	animal.speak();
}
// 如果执行时想让猫说话,就不能进行早绑定
class CatVir : public Animal {
public:
	// 虚函数实现地址晚绑定
	void speak() {
		cout << "cat speak " << endl;
	}
};


void test01() {
	cout << "地址早绑定" << endl;
	Cat cat;
	doSpeak(cat);
	cout << "addr 晚绑定" << endl;
	CatVir catvir;
	doSpeak(catvir);
}

int main() {
	test01();
	return 0;
}

52、动态多态的原理剖析

#include <iostream>
using namespace std;

class AnimalOrg {
public:
	// ------------ 动态多态  -------------- 地址的晚绑定:运行阶段确定函数 ------------
	// 加了 virtual 后, 会优先从继承的类中寻找函数, 找不到再从父类中找
	// 这个就是地址的晚绑定
	// 否则会优先从父类中寻找,这个就是地址的早绑定
	void speak() {
		cout << "animal speak " << endl;
	}
};

class AnimalChg {
public:
	// vfptr: 虚函数指针(虚函数表指针
	// vitual function pointer
	// AnimalChg::vftable 内部会记录虚函数的地址 ,
	virtual void speak() {
		cout << "animal speak " << endl;
	}
};

class Cat : public AnimalOrg {
public: 
	// 当子类重写了父类中的虚函数, 父类中的虚函数表会将父类中的虚函数表替换为子类的虚函数
	// 从而确定函数的入口地址
	//只是提换子类中的虚函数表
	// animla& animal = cat -->会从cat的虚函数表中找cat的speak函数
	void speak() {
		cout << "cat speak " << endl;
	}
};

void doSpeak(AnimalOrg& animal) {
	animal.speak();
}

void test01() {
	cout << "sizeof animlaOrg = " << sizeof(AnimalOrg) << endl; // 1 bits
	cout << "sizeof animalChg = " << sizeof(AnimalChg) << endl; // 8 bits 指针 和电脑有关 32位->4 bits
}

int main() {
	test01();
	return 0;
}

53、多态案例:计算机类

#include <iostream>
using namespace std;

class Calculator {
public:
	int num1;
	int num2;
	int getResult(string oper) {
		if (oper == "+") {
			return num1 + num2;
		}
		else if (oper == "-") {
			return num1 - num2;
		}
		else if (oper == "*") {
			return num1 * num2;
		}
		// 如果需要添加新的功能,需要修改源码
		// 对扩展进行开放,对修改进行关闭
	}
};

void test01() {
	Calculator c;
	c.num1 = 10;
	c.num2 = 9;

	cout << c.num1 << "+" << c.num2 << "=" << c.getResult("+") << endl;
	cout << c.num1 << "-" << c.num2 << "=" << c.getResult("-") << endl;
	cout << c.num1 << "*" << c.num2 << "=" << c.getResult("*") << endl;
}

// 利用多态来写计算器
class AbstructCalc {
public:
	int num1;
	int num2;
	virtual int getResult() {
		return 0;
	}
};

class Add : public AbstructCalc {
public:
	int getResult() {
		return num1 + num2;
	}
};

class Sub : public AbstructCalc {
public:
	int getResult() {
		return num1 - num2;
	}
};

void test02() {
	// 父类的指针指向子类的对象
	AbstructCalc* abc = new Add;
	abc->num1 = 10;
	abc->num2 = 19;
	cout << abc->num1 << "+" << abc->num2 << "=" << abc->getResult() << endl;
	// 用完后记得销毁
	delete abc;
	abc = NULL;

	AbstructCalc* abc1 = new Sub;
	abc1->num1 = 10;
	abc1->num2 = 19;
	cout << abc1->num1 << "-" << abc1->num2 << "=" << abc1->getResult() << endl;
	// 用完后记得销毁
	delete abc;
}

int main() {
	test02();
	return 0;
}

54、纯虚函数和抽象类

#include <iostream>
using namespace std;

// 抽象类
class Base {
public:
	// 纯虚函数
	// 无法实例化对象, 只能被继承
	virtual void func() = 0;
};

class Son : public Base {
public:
	void func() {
		cout << "rewrite func from father" << endl;
	}
};

int main() {

	Son s;
	s.func();
	// 多态写法
	Base* p = new Son;
	p->func();

	return 0;
}

55、多态案例:制作饮品

#include <iostream>
using namespace std;

// 多态的案例二,制作饮品

class AbstructDrinking {
public:
	virtual void Boild() = 0;
	virtual void Brew() = 0;
	virtual void PourCup() = 0;
	virtual void PutSomething() = 0;
	// 制作饮品
	void makeDrink() {
		Boild();
		Brew();
		PourCup();
		PutSomething();
	}
};

class Coffee : public AbstructDrinking {
public:
	void Boild() {
		cout << "煮水" << endl;
	}
	void Brew() {
		cout << "冲泡茶叶" << endl;
	}
	void PourCup() {
		cout << "倒入茶杯" << endl;
	}
	void PutSomething() {
		cout << "加入枸杞" << endl;
	}
};

void test01() {
	AbstructDrinking* abs = new Coffee;
	abs->makeDrink();
	delete abs;
}

int main() {
	test01();
	return 0;
}

56、虚析构和纯析构

#include <iostream>
using namespace std;

class Animal {
public:
	Animal() {
		cout << "animal __init__" << endl;
	}
	// 将父类的析构函数变为虚析构函数 父类指针释放类对象不干净的问题 -------------> 虚析构:有声明有实现
	/*
		virtual ~Animal() {
		cout << "animal __del__" << endl;
	}
	*/

	// -------------------------------------------纯析构---------------需要代码实现,只有声明
	// 纯析构之后这个类也属于抽象类
	virtual ~Animal() = 0;

	// 虚函数
	virtual void speak() = 0;
};
// 虚构的实现
Animal::~Animal() {
	cout << "Animal__del__" << endl;
}

class Cat : public Animal {
public:
	string* name;
	Cat(string name) {
		cout << "cat __init__" << endl;
		this->name = new string(name);
	}
	~Cat() {
		if (name != NULL) {
			// delete father pointer 不会调用这一行,但是可以利用虚析构来解决这个问题
			cout << "cat __del__" << endl;
			delete name;
		}
	}
	void speak() {
		cout << *name << "小猫在说话" << endl;
	}

};

void test01() {
	Animal* animal = new Cat("tom");
	animal->speak();
	delete animal;
}

int main() {
	test01();
	return 0;
}

57、实例:电脑组装

#include <iostream>
using namespace std;


class Cpu {
public:
	virtual void calculate() = 0;
};

class VideoCard {
public:
	virtual void display() = 0;
};

class Memory {
public:
	virtual void storage() = 0;
};


class Computer {
public:
	Computer(Cpu* cpu_, VideoCard* vediocard_, Memory* memory_) {
		cpu = cpu_;
		videoCard = vediocard_;
		memory = memory_;
	}
	void work() {
		cpu->calculate();
		videoCard->display();
		memory->storage();
	}
	~Computer() {
		if (cpu != NULL && videoCard != NULL && memory != NULL) {
			delete cpu;
			delete videoCard;
			delete memory;
		}
	}

private:
	Cpu* cpu;
	VideoCard* videoCard;
	Memory* memory;
};

// 具体厂商
class InterCpu : public Cpu {
public:
	virtual void calculate() {
		cout << "inter cpu work !" << endl;
	}
};
class InterVideoCard : public VideoCard {
public:
	virtual void display() {
		cout << "inter videoCard work !" << endl;
	}
};
class InterMemory : public Memory {
public:
	virtual void storage() {
		cout << "inter Memory work !" << endl;
	}
};

void test() {
	Cpu* cpu = new InterCpu;
	VideoCard* ved = new InterVideoCard;
	Memory* memory = new InterMemory;
	Computer* computer = new Computer(cpu, ved, memory);
	computer->work();
	delete computer;
	cpu = NULL;
	ved = NULL;
	memory = NULL;
}

int main() {
	test();
	return 0;
}

58、文件操作:写文件

#include<iostream>
using namespace std;

#include<fstream>

// 文本文件中的写文件

void test01() {
	// 创建流对象
	// output file stream
	ofstream ofs;
	// 指定打开的方式, ios(input-output-stream)
	ofs.open("test61.txt", ios::out);
	// 写内容
	ofs << "name:alex\nsex:female\nage:18" << endl;
	ofs.close();
}

int main() {
	test01();
	return 0;
}

59、文件操作:读文件

#include <iostream>
using namespace std;

#include<fstream>
#include<string>


void test01() {
	// 创建文件流对象
	ifstream ifs;
	// 打开文件
	ifs.open("test61.txt", ios::in);
	// 判断是否打开
	if (!ifs.is_open()) {
		cout << "文件打开失败了" << endl;
		return;
	}
	// 读文件
	// 第一种-----每一次写入都会覆盖上一次的写入
	/*
	char buf[1024] = { 0 };
	while (ifs >> buf) {
		cout << buf << endl;
	}

	cout << buf << "========" << endl;
	ifs.close();*/
	// 第二种
	/*
	char buf[1024] = { 0 };
	while (ifs.getline(buf, sizeof(buf))) {
		cout << buf << endl;
		;
	};
	*/

	// 第三种
	string buf;
	
	// 包含头文件 string
	/*
	while (getline(ifs, buf)) {
		cout << buf << endl;
	}
	ifs.close();
	*/

	// 第四种, EOF == end of line
	char c;
	while ((c = ifs.get()) != EOF) {
		cout << c;
	}
	ifs.close();
}

int main() {
	test01();
	return 0;
}

60、二进制写文件

#include <iostream>
using namespace std;
#include<fstream>

// 二进制写文件
struct Person {
	char name[64];
	int age;
};

void test01() {
	ofstream ofs("binary63.txt", ios::out | ios::binary);
	Person p = { "张三", 18 };
	ofs.write((const char*)&p, sizeof(p));
	ofs.close();
}

int main() {
	test01();
	return 0;
}

61、二进制读文件

#include <iostream>
using namespace std;
#include<fstream>

struct Person {
	char name[64];
	int age;
};

// 二进制文件写入的是数据的指针,读文件时也是用的一个指针来储存读出来的指针内容
// 二进制的文件读写用的指针都必须要强制转化为 char 类型的指针变量
// 二进制写文件时用的是 常量指针
// 二进制读文件时用的就是普通的指针

void test01() {

	ifstream ifs;
	ifs.open("binary63.txt", ios::in | ios::binary);

	if (!ifs.is_open()) {
		cout << "error !" << endl;
		return;
	}
	Person p;
	ifs.read((char*)&p, sizeof(Person));
	cout << p.name << "\t" << p.age << endl;
}


int main() {
	test01();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值