自学黑马C++核心编程,提高编程

#include<iostream>
#include<string>
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 IntelCPU :public CPU
{
	void calculate()
	{
		cout << "IntelCPU is working" << endl;
	}
};

class IntelVideoCard :public VideoCard
{
	void display()
	{
		cout << "IntelVideoCard is working" << endl;
	}
};


class IntelMemory :public Memory
{
	void storage()
	{
		cout << "IntelMemory is working" << endl;
	}
};

class LenovoCPU :public CPU
{
	void calculate()
	{
		cout << "LenovoCPU is working" << endl;
	}
};

class LenovoVideoCard :public VideoCard
{
	void display()
	{
		cout << "LenovoVideoCard is working" << endl;
	}
};


class LenovoMemory :public Memory
{
	void storage()
	{
		cout << "LenovoMemory is working" << endl;
	}
};

class Computer
{
public:
	Computer(CPU*cpu,VideoCard*vc,Memory*me)
	{
		m_cpu = cpu;
		m_vc = vc;
		m_me = me;
	}

	void dowork()
	{
		m_cpu->calculate();
		m_me->storage();
		m_vc->display();
	}
	//老师好,这个案例中为什么Computer类析构时,不需要设置为虚析构函数?

	~Computer()
	{
		cout << "call of Computer desconstructor" << endl;
		if (m_cpu != NULL)
		{
			delete m_cpu;
			m_cpu = NULL;
		}

		if (m_vc != NULL)
		{
			delete m_vc;
			m_vc = NULL;
		}

		if (m_me != NULL)
		{
			delete m_me;
			m_me = NULL;
		}
	}
private:
	CPU* m_cpu;
	VideoCard* m_vc;
	Memory* m_me;
};
//多态的条件:
//父类指针或者引用指向子类
void test01()
{
	//第一台电脑的零件
	CPU *incpu = new IntelCPU;
	VideoCard* invc = new IntelVideoCard;
	Memory* inme = new IntelMemory;
	//组装第一台电脑
	Computer *c1 = new Computer(incpu, invc, inme);
	c1->dowork();
	delete c1;
	cout << "--------------------------------------------" << endl;
	//第二台电脑的零件
	CPU* lecpu = new LenovoCPU;
	VideoCard* levc = new LenovoVideoCard;
	Memory* leme = new LenovoMemory;
	//第二台电脑
	Computer* c2 = new Computer(lecpu, levc, leme);
	c2->dowork();
	delete c2;

}
int main()
{
	test01();
}

学习目标:

考前学完 黑马 C++核心知识


学习内容:

C++核心编程部分

    内存分区模型
        程序运行前
        程序运行后
        new运算符
    引用
        基本使用
        注意事项
        做函数参数
        做函数的返回值
        引用本质
        常量引用
    函数提高
        函数默认参数
        函数占位参数
        函数重载
        函数重载的注意事项
    类和对象
        封装
            封装的意义
            封装的意义一
            例子
            封装的意义二
            struct和class
            练习案例
                (1)设计立方体类
                (2)点和圆的关系
        对象的初始化清理
            构造函数和析构函数
                构造函数语法
                析构函数语法
            构造函数的分类及调用
            拷贝构造函数调用时机
            构造函数的调用规则
            深拷贝与浅拷贝
            初识化列表
            类对象作为类成员
            静态成员
        C++对象模型和this指针
            成员变量和成员函数分开存储
            this指针的概念
            空指针返回成员函数
            const修饰成员函数
        友元
            全局函数做友元
            类做友元
            成员函数做友元
        运算符重载
            加号运算符重载
            左移运算符重载
            递增运算符重载
            赋值运算符重载
            关系运算符重载
            函数调用运算符重载
        继承
            继承的基本语法
            继承方式
            继承中的对象模型
            继承中构造和析构的顺序
            继承同名成员处理方式
            继承同名静态成员处理方式
            多继承语法
            菱形继承
        多态
            多条的基本概念
            多态的原理剖析
            多态案例1——计算器类
            纯虚函数和抽象类
            多态案例2——制作饮品
            虚析构和纯虚析构
            多态案例3——电脑组装
    文件操作
            文本文件
                写文件
                读文件
            二进制文件
                写文件
                读文件
————————————————
版权声明:本文为CSDN博主「半生瓜のblog」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_51604330/article/details/118607922


学习时间:

1.课堂时间 周二和周四

2.课下时间 周末


学习产出:

1.自主复现黑马教程中的代码

2.考试取得高分

2023年5月28日

P110 深拷贝和浅拷贝

问题的产生

问题的解决

class Person {
public:
	//无参(默认)构造函数
	Person() {
		cout << "无参构造函数!" << endl;
	}
	//有参构造函数
	Person(int age ,int height) {
		
		cout << "有参构造函数!" << endl;

		m_age = age;
		m_height = new int(height);
		
	}
	//拷贝构造函数  
	Person(const Person& p) {
		cout << "拷贝构造函数!" << endl;
		//如果不利用深拷贝在堆区创建新内存,会导致浅拷贝带来的重复释放堆区问题
		m_age = p.m_age;
		m_height = new int(*p.m_height);
		
	}

	//析构函数
	~Person() {
		cout << "析构函数!" << endl;
		if (m_height != NULL)
		{
			delete m_height;
		}
	}
public:
	int m_age;
	int* m_height;
};

void test01()
{
	Person p1(18, 180);

	Person p2(p1);

	cout << "p1的年龄: " << p1.m_age << " 身高: " << *p1.m_height << endl;

	cout << "p2的年龄: " << p2.m_age << " 身高: " << *p2.m_height << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

2023年5月1日

P119 友元 友元类

1.类的声明

2.类外写成员函数,需要在类内声明

​

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

class Building;//类的声明,不写的话,在定义 GoodGay类时会报错

class GoodGay
{
public:
	GoodGay();
public:
	void visit();

	Building* building;
};

class Building
{
public:
	Building();
public:
	string sittingroom;
private:
	string bedroom;

};


//类外写成员函数,需要在类内事先声明
GoodGay::GoodGay()
{
	building = new Building;
}

Building::Building()
{
	sittingroom = "客厅";
	bedroom = "卧室";
}

void GoodGay::visit()
{
	cout << "GoodGay assesses " << building->sittingroom << endl;
}

void test01()
{
	GoodGay gy;
	gy.visit();
}

int main()
{
	test01();
	system("pause");
	return 0;
}

[点击并拖拽以移动]
​

 BUG:

 此次出错原因:

没写主函数导致的

P120 成员函数做友元

1. 关键代码:注意表明visit是某类的成员函数,而不是全局函数

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

class Building;//类的声明,不写的话,在定义 GoodGay类时会报错

class GoodGay
{
public:
	GoodGay();
public:
	void visit();//让visit函数可以访问building中私有函数
	void visit2();//让visit2函数不可以访问building中私有函数
	Building* building;
};

class Building
{
    //关键代码
    //注意GoodGay:: 这样可表明visit是GoodGay类的成员函数而不是成员函数,否则报错
	//告诉编译器GoodGay下成员函数visit作为本类的好朋友,可以访问私有内容
	friend void GoodGay::visit();
public:
	Building();
public:
	string sittingroom;
private:
	string bedroom;
};
//类外生成成员函数
Building::Building()
{
	sittingroom = "客厅";
	bedroom = "卧室";
}

GoodGay::GoodGay()
{
	building = new Building;
}

void GoodGay::visit()
{
	cout << "GoodGay visit accesses " << building->sittingroom << endl;

	cout << "GoodGay visit accesses " << building->bedroom << endl;
}

void GoodGay::visit2()
{
	cout << "GoodGay visit2 accesses " << building->sittingroom << endl;

	/*cout << "GoodGay visit2 accesses " << building->bedroom << endl;*/
}
void test01()
{
	GoodGay gy;
	gy.visit();
	gy.visit2();
}

int main()
{
	test01();
	system("pause");
	return 0;
}

2023年5月2日

P121 加号运算符重载

 知识点:

1.成员函数重载

2.全局函数重载

3.运算符重载时,可以函数重载

4.复习了函数重载的概念,引用的本质

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

class Person
{
public:
	int m_a = 10;
	int m_b = 10;
	//1.成员函数重载加号运算符
	Person operator+(Person &p)
	{
     
		Person temp;
		temp.m_a = this->m_a + p.m_a;
		temp.m_b = this->m_b + p.m_b;
		return temp;
    }
};

//2.全局函数重载加号
Person operator+(Person& p1, Person& p2)
{
	Person temp;
	temp.m_a = p1.m_a + p2.m_a;
	temp.m_b = p1.m_b + p2.m_b;
	return temp;
}

//运算符重载,可以发生函数重载
Person operator+(Person& p1, int val)
{
	Person temp;
	temp.m_a = p1.m_a + val;
	temp.m_b = p1.m_b + val;
	return temp;
}

void test01()
{
	Person p1;
	p1.m_a = 10;
	p1.m_b = 10;


	Person p2;
	p2.m_a = 10;
	p2.m_b = 10;

	Person p3;

	/*p3 = p1.personAddperson(p2);
	p3 = pAddp(p1, p2);*/
	/*p3 = p1 + p2;*/
	//成员函数重载本质调用
	/*p3 = p1.operator+(p2);*/
	//全局函数重载本质调用
	//p3 = operator+(p1,p2);
	p3 = p1 + 10;
	cout << "p3.m_a= " << p3.m_a << endl;
	cout << "p3.m_b= " << p3.m_b << endl;
}

int main()
{
	test01();
	system("pause");
	return 0;
}

P122 左移运算符重载

1.不能用成员函数实现左移运算符重载,因为成员函数无法实现cout在左侧

2.疑问? 为什么重载函数的形参类型需要是 ostream& ?

函数的形参列表中三种传参数的方式:

这是引用传递,可见

**作用:**函数传参时,可以利用引用的技术让形参修饰实参

**优点:**可以简化指针修改实参
//1. 值传递
void mySwap01(int a, int b) {
	int temp = a;
	a = b;
	b = temp;
}

//2. 地址传递
void mySwap02(int* a, int* b) {
	int temp = *a;
	*a = *b;
	*b = temp;
}

//3. 引用传递
void mySwap03(int& a, int& b) {
	int temp = a;
	a = b;
	b = temp;
}

int main() {

	int a = 10;
	int b = 20;

	mySwap01(a, b);
	cout << "a:" << a << " b:" << b << endl;

	mySwap02(&a, &b);
	cout << "a:" << a << " b:" << b << endl;

	mySwap03(a, b);
	cout << "a:" << a << " b:" << b << endl;

	system("pause");

	return 0;
}

#include<iostream>
#include<string>
using namespace std;
//不能用成员函数实现左移运算符重载,因为无法实现cout在左侧
class Person
{
	friend ostream& operator<<(ostream& out, Person& p);
public:
	Person(int a ,int b)
	{
		this->m_a = a;
		this->m_b = b;
	}
private:
	int m_a;
	int m_b;
};

ostream & operator<<(ostream & out, Person& p)
{
	out << "p.m_a = " << p.m_a << " p.m_b = " << p.m_b;
	return out;
}

void test01()
{
	Person p(10,10);
	
	
	cout << p << "hello world" << endl; //链式编程
}

int main()
{
	test01();
	system("pause");
	return 0;
};

2023年5月4日

P123 递增运算符重载

1.//重载前置递增返回类型为数值时

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

class Myinteger
{
	friend ostream& operator<<(ostream& cout, Myinteger myint);
public:
	Myinteger()
	{
		m_num = 0;
	}
	//重载前置++
	//重载前置递增返回类型为数值时
	Myinteger operator++()
	{
		//先++
		++m_num;
		//再返回
		return *this;
	}
	//后置运算符重载
	//Myinteger operator++(int) int表示占位参数,可以用于区分前置和后置递增
	Myinteger operator++(int)
	{
		//先记录目前的值
		Myinteger temp = *this;
		//再进行递增
		this->m_num++;
		//最后返回记录的值
		return temp;
	}
private:
	int m_num;
};

ostream& operator<<(ostream&cout,Myinteger myint)
{
	cout << myint.m_num << endl;
	return cout;
}


void test01()
{
	Myinteger num1;
	cout << num1;
}

void test02()
{
	Myinteger myint;
	cout << ++myint<<endl;
	cout << ++myint<<endl;
	cout << myint<<endl;
}

void test03()
{
	Myinteger myint;
	cout << myint++;
	cout << myint;
}

void test04()
{
	Myinteger myint;
	cout << ++(++myint) << endl;
	cout << myint;
}

int main()
{
	//test02();
	/*test03();*/
	test04();
	system("pause");
	return 0;
}

 2.//重载前置递增返回类型为引用时

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

class Myinteger
{
	friend ostream& operator<<(ostream& cout, Myinteger myint);
public:
	Myinteger()
	{
		m_num = 0;
	}
	//重载前置++
	//重载前置递增返回类型为数值时
	Myinteger & operator++()
	{
		//先++
		++m_num;
		//再返回
		return *this;
	}
	//后置运算符重载
	//Myinteger operator++(int) int表示占位参数,可以用于区分前置和后置递增
	Myinteger operator++(int)
	{
		//先记录目前的值
		Myinteger temp = *this;
		//再进行递增
		this->m_num++;
		//最后返回记录的值
		return temp;
	}
private:
	int m_num;
};

ostream& operator<<(ostream&cout,Myinteger myint)
{
	cout << myint.m_num << endl;
	return cout;
}


void test01()
{
	Myinteger num1;
	cout << num1;
}

void test02()
{
	Myinteger myint;
	cout << ++myint<<endl;
	cout << ++myint<<endl;
	cout << myint<<endl;
}

void test03()
{
	Myinteger myint;
	cout << myint++;
	cout << myint;
}

void test04()
{
	Myinteger myint;
	cout << ++(++myint) << endl;
	cout << myint;
}

int main()
{
	//test02();
	/*test03();*/
	test04();
	system("pause");
	return 0;
}

 总结:

//重载前置++ ,返回引用是为了一直对一个数据进行操作
    // 如果返回数值,那么第一次递增后,返回的就是一个新的数据

最终版代码

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

class Myinteger
{
	friend ostream& operator<<(ostream& cout, Myinteger myint);
public:
	Myinteger()
	{
		m_num = 0;
	}
	//重载前置++ ,返回引用是为了一直对一个数据进行操作
	// 如果返回数值,那么第一次递增后,返回的就是一个新的数据
	//重载前置递增返回类型为数值时
	Myinteger & operator++()
	{
		//先++
		++m_num;
		//再返回
		return *this;
	}
	//后置运算符重载
	//Myinteger operator++(int) int表示占位参数,可以用于区分前置和后置递增
	Myinteger operator++(int)
	{
		//先记录目前的值
		Myinteger temp = *this;
		//再进行递增
		this->m_num++;
		//最后返回记录的值
		return temp;
	}
private:
	int m_num;
};

ostream& operator<<(ostream&cout,Myinteger myint)
{
	cout << myint.m_num << endl;
	return cout;
}


void test01()
{
	Myinteger num1;
	cout << num1;
}

void test02()
{
	Myinteger myint;
	cout << ++myint<<endl;
	cout << ++myint<<endl;
	cout << myint<<endl;
}

void test03()
{
	Myinteger myint;
	cout << myint++;
	cout << myint;
}

void test04()
{
	Myinteger myint;
	cout << ++(++myint) << endl;
	cout << myint;
}

int main()
{
	//test02();
	/*test03();*/
	test04();
	system("pause");
	return 0;
}

作业:重载递减运算符

疑问:重载后置的递减运算符无法一直对一个数据操作吗?

#include<iostream>
using namespace std;

class Myinteger
{
	friend ostream& operator<<(ostream& cout, Myinteger myint);
public:
	Myinteger()
	{
		m_num = 10;
	}
//重载前置递减运算符
	Myinteger& operator--()
	{
		//第一步:递减
		--m_num;

		//第二步:输出递减后的数据
		return *this;
	}
//重载后置递减运算符
	Myinteger operator--(int)
	{
		//第一步:储存当前的值
		Myinteger myint = *this;
		//第二步:对当前值进行递减
		m_num--;
		//第三步:输出当前的值
		return *this;
	}
private:
	int m_num;

};

//重载左移运算符
ostream& operator<<(ostream& cout, Myinteger myint)
{
	cout << myint.m_num << endl;
	return cout;
}

void test01()
{
	Myinteger myint;
	cout << --(--myint) << endl;

}

void test02()
{
	Myinteger myint;
	cout << "this test02" << endl;
	cout <<( myint--) --<< endl;
	cout << myint<< endl;
}
int main()
{
	test01();
	test02();
	system("pause");
	return 0;
}

2023年5月6日

P124 赋值运算符重载

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

class Person
{

public:
	Person(int a)
	{
		m_age = new int(a);
	}
	//析构函数
	~Person()
	{
		if (m_age != NULL)
		{
			delete m_age;
			m_age = NULL;
		}
	}
	//赋值运算符重载
	Person& operator=(Person &p1)
	{
		if (m_age != NULL)
		{
			delete m_age;
			m_age = NULL;
		} 
		//编译器提供的为浅拷贝
		//m_age=p1.m_age;
		//深拷贝,解决浅拷贝的问题
		m_age = new int(*p1.m_age);
		return *this;
	}

	int* m_age;
};

void test01()
{
	Person p1(18);
	Person p2(20);
	Person p3(30);
	p3 = p2 = p1;
	cout << "p1=" <<* p1.m_age << endl;
	cout << "p2=" <<* p2.m_age << endl;
	cout << "p3=" <<* p3.m_age << endl;
}

int main()
{
	test01();
	system("pause");
	return 0;
}

P125 关系运算符重载

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

class Person
{
public:
	string m_name;
	int m_age;
	Person(string name, int age)
	{
		m_name = name;
		m_age = age;
    }

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

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

};

void test01()
{
	Person p1("tom", 18);
	Person p2("jim", 18);
	if (p1 == p2)
	{
		cout << "p1 and p2 are  same" << endl;
	}
	else { cout << "p1 and p2 are different" << endl; }

	if (p1 != p2)
	{
		cout << "p1 and p2 are  different" << endl;
	}
	else { cout << "p1 and p2 are same" << endl; }
	
}

int main()
{
	test01();

}

2023年5月7日

P126 函数调用运算符重载

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

class MyFunc
{
public:
	void operator()(string test)
	{
		cout << test << endl;
	}
};

void myprint(string test)
{
	cout << test << endl;
}
void test01()
{
	//重载的()操作符 也称为仿函数
	MyFunc myfunc;
	//对象使用重载过后的小括号,由于使用起来非常像函数调用,故称为仿函数
	myfunc("hello world");
	//函数调用
	myprint("hello world");
}

class MyAdd
{
public:
	int operator()(int a,int b)
	{
		return a + b;
	}
};

void test02()
{
	MyAdd myadd;
	cout << myadd(100, 100) << endl;
	//匿名对象调用  
	cout << MyAdd()(100, 100) << endl;
}
int main()
{
	test01();
	test02();
}

P127 继承的基本语法

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

class basepage
{
public:
	void header()
	{
		cout << "首页、公开课、登录、注册...(公共头部)" << endl;
	}
	void footer()
	{
		cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
	}
	void left()
	{
		cout << "Java,Python,C++...(公共分类列表)" << endl;
	}
};

class java :public basepage
{
public:
	void content()
	{
		cout << "java 视频" << endl;
	}
};

class cpp :public basepage
{
public:
	void content()
	{
		cout << "cpp 视频" << endl;
	}
};

class python :public basepage
{
public:
	void content()
	{
		cout << "python视频" << endl;
	}
};

void test01()
{
	java ja;
	ja.header();
	ja.footer();
	ja.left();
	ja.content();
	cout << "-------------------------" << endl;
	cpp cp;
	cp.header();
	cp.footer();
	cp.left();
	cp.content();
	cout << "-------------------------" << endl;
	python py;
	py.header();
	py.footer();
	py.left();
	py.content();

}

int main()
{
	test01();
}

总结:

继承的好处:可以减少重复的代码

class A : public B;

A 类称为子类 或 派生类

B 类称为父类 或 基类

派生类中的成员,包含两大部分

一类是从基类继承过来的,一类是自己增加的成员。

从基类继承过过来的表现其共性,而新增的成员体现了其个性。

P128 继承的方式

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

class base1
{
public:
	int m_a;
protected:
	int m_b;
private:
	int m_c;
};
//公共继承
class son1 :public base1
{
public:
	void fun()
	{
		m_a = 10;//公共继承:父类中公共成员 到子类中仍为公共权限
		m_b = 10;//公共继承:父类中保护成员 到子类中仍为保护权限
		//m_c = 10;//公共继承:父类中私有成员 子类访问不到

	}
};


void test01()
{
	son1 s1;
	s1.m_a = 100;//公共权限,类内类外均可访问
	//s1.m_b = 100;//到son1中,m_b时保护权限,类外不可访问
}
//保护继承
class son2 :protected base1
{
public:
	void fun()
	{
		m_a = 10;//保护继承中:父类中公共成员 到子类中变为保护权限
		m_b = 10;//保护继承中:父类中保护成员 到子类中仍为保护权限
		//m_c = 10;//保护继承中:父类中私有成员 子类访问不到
	}
};

void test02()
{
	son2 s1;
	//s1.m_a = 100;//到son2中,m_a是保护权限,类外不可访问
	//s1.m_b = 100;//到son2中,m_b是保护权限,类外不可访问
}

//私有继承
class son3 :private base1
{
public:
	void fun()
	{
		m_a = 10;//私有继承中:父类中公共成员 到子类中变为私有权限
		m_b = 10;//私有继承中:父类中保护成员 到子类中变为私有权限
		//m_c = 10;//私有继承中:父类中私有成员 子类访问不到
	}
};

void test03()
{
	son3 s1;
	//s1.m_a = 100;//到son3中,m_a是私有权限,类外不可访问
	//s1.m_b = 100;//到son3中,m_b是私有权限,类外不可访问
}

class grandson : public son3
{
	void fun()
	{
		//m_a = 10;//到son3中,m_a是私有权限,派生类不可访问
	}
};

总结:

1.继承方式为public,则子类继承的成员的权限最低为public,若高于public则不变

2.继承方式为protected,则子类继承的成员的权限最低为protected,若高于protected则不变


3.继承方式为private,则子类继承的成员的权限均为private

4.private与protected的异同

privateprotected
类外不可访问类外不可访问
派生类不可访问派生类可以访问

P129 继承中的对象模型

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

class base1
{
public:
	int m_a;
protected:
	int m_b;
private:
	int m_c;//私有成员只是被编译器隐藏了,但还是会继承下去
};
//利用开发人员命令提示工具查看对象模型
//跳转盘符 D: (跳转至目标文件所在的盘)
//跳转文件路径 cd 具体路径下
//查看命名
//cl /d1 reportSingleClassLayout类名 文件名
//文件名可以通过输入文件名开头,再按tab的方式实现自动补齐
class son1 : public base1
{
public:
	int m_d;
};

void test01()
{
	cout << "sizeof(son1):" << sizeof(son1) << endl;
}

int main()
{
	test01();
}

命令行工具: Developer Command Prompt for VS 2022

//利用开发人员命令提示工具查看对象模型
//跳转盘符 D: (跳转至目标文件所在的盘)
//跳转文件路径 cd 具体路径下
//查看命名
//cl /d1 reportSingleClassLayout类名 文件名
//文件名可以通过输入文件名开头,再按tab的方式实现自动补齐

cl /d1 reportSingleClassLayoutson1 047.cpp

 结论: 父类中私有成员也是被子类继承下去了,只是由编译器给隐藏后访问不到

P130 继承-构造和析造的顺序

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

class base
{
public:
	base()
	{
		cout << "constructor of base" << endl;

	}

	~base()
	{
		cout << "deconstructor of base" << endl;
	}
};

class son : public base
{
public:
	son()
	{
		cout << "constructor of son" << endl;

	}

	~son()
	{
		cout << "deconstructor of son" << endl;
	}
};
//继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反
void test01()
{
	son s1;
}

int main()
{
	test01();
}

总结:继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反

P131 继承 同名成员处理

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

class base
{
public:
	base()
	{
		 m_a = 100;
}
	int m_a;

	void func()
	{
		cout << "base-func of " << endl;
	}

	void func(int a)
	{
		cout << "base-func of int a" << endl;
}
};

class son : public base
{
public:
	son()
	{
		 m_a = 200;
	}
	int m_a;


	void func()
	{
		cout << "son-func" << endl;
	}
};
//同名成员属性的调用
void test01()
{
	son s1;
	cout << "son   :" << s1.m_a << endl;
	//如果想通过子类访问到父类中的同名成员,需要加一个父类的作用域
	cout << "base  :" << s1.base::m_a << endl;
}
//同名成员函数的调用
void test02()
{
	son s;
	s.func();//直接调用,调用的是子类中的同名成员函数 

	//如何调用到父类中的成员函数
	s.base::func();
	//当子类与父类拥有同名的成员函数,子类会隐藏父类中所有版本的同名成员函数
	//如果想访问父类中被隐藏的同名成员函数,需要加父类的作用域
	//s.func(100);
}
int  main()
{
	test01();
	test02();
	return 0;
}

总结:

1. 子类对象可以直接访问到子类中同名成员

2. 子类对象加作用域可以访问到父类同名成员

3. 当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数

P132 继承 同名静态成员函数处理

#include<iostream>
#include<string>
using namespace std;
//注意静态成员属性的特质
//静态成员变量特点:
	//1 在编译阶段分配内存
	//2 类内声明,类外初始化
	//3 所有对象共享同一份数据
class base
{
public:
	static int m_a;
	static void func()
	{
		cout << "base func" << endl;
    }

	static void func(int a)
	{
		cout << "base func of int a" << endl;
	}



};
int base::m_a = 100;
class son : public base
{
public:
	static int m_a;
	static void func()
	{
		cout << "son func" << endl;
	}

	
};
int son::m_a = 200;
//同名静态成员属性
void test01()
{
	son s;
	//1.通过对象访问
	cout << "通过对象访问" << endl;
	cout << "son :" << s.m_a << endl;
	cout << "base:" << s.base::m_a << endl;
	//2.通过类名访问
	cout << "通过类名访问" << endl;
	cout << "son :" << son::m_a << endl;
	cout << "base:" << son::base::m_a << endl;
}

void test02()
{
	son s;
	//1.通过对象访问
	cout << "通过对象访问" << endl;
	s.func();
	s.base::func();
	//2.通过类名访问
	cout << "通过类名访问" << endl;
	son::func();
	son::base::func();
	son::base::func(100);
	//son::func(100);//出现同名,子类会隐藏掉父类中所有同名成员函数,需要加作作用域访问
	son::base::func(100);
}
int main()
{
	test01();
	test02();
}

 两个冒号的作用:

总结:同名静态成员处理方式和非静态处理方式一样,只不过有两种访问的方式(通过对象 和 通过类名)

P133 继承 多继承语法

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

class base1
{
public:
	int m_a;
	base1()
	{
		m_a = 100;
}
};

class base2
{
public:
	int m_a;
	base2()
	{
		m_a = 200;
	}
};

class son :public base1, public base2
{

};

void test02()
{
	son s;
	cout << "base1 m_a= " << s.base1::m_a << endl;
	cout << "base2 m_a= " << s.base2::m_a << endl;
}

int main()
{
	test02();
}

 总结:同名静态成员处理方式和非静态处理方式一样,只不过有两种访问的方式(通过对象 和 通过类名)

P134 继承 菱形继承问题及其解决方法

无虚继承时

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

class Animal
{
public:
	int m_Age;
	Animal()
	{
		m_Age = 18;
	}
};
//利用虚继承解决菱形继承导致的问题

class Sheep : public Animal
{
	
};
 
class Tuo :public Animal
{

};

class SheepTuo : public Sheep, public Tuo
{

};

void test01()
{
	SheepTuo st;
	/*st.m_Age = 38;*/
	st.Sheep::m_Age = 18;
	st.Tuo::m_Age = 28;
	/*菱形继承 两个父类拥有相同数据,需要加作用域加以区分*/
	cout << "st.Sheep::m_Age =" << st.Sheep::m_Age << endl;
	cout << "st.Tuo::m_Age = " << st.Tuo::m_Age << endl;
	/*cout << "st.m_Age = " << st.m_Age << endl;*/
	//菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义
	cout << "sizeof(st) = " << sizeof(st) << endl;
}

int main()
{
	test01();
}

没有使用虚基类之前的模式

 有虚继承时

//变为虚继承后,相当于只有一份数据,也多了一种访问方式。但三种访问方式访问到的都是同一份数据

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

class Animal
{
public:
	int m_Age;
	Animal()
	{
		m_Age = 18;
	}
};
//利用虚继承解决菱形继承导致的问题

class Sheep :virtual public Animal
{
	
};
 
class Tuo :virtual public Animal
{

};

class SheepTuo : public Sheep, public Tuo
{

};

void test01()
{
	SheepTuo st;
	st.m_Age = 38;
	st.Sheep::m_Age = 18;
	st.Tuo::m_Age = 28;
	/*菱形继承 两个父类拥有相同数据,需要加作用域加以区分*/
	cout << "st.Sheep::m_Age =" << st.Sheep::m_Age << endl;//Sheep:: 表示作用域
	cout << "st.Tuo::m_Age = " << st.Tuo::m_Age << endl;
	//变为虚继承后,相当于只有一份数据
	cout << "st.m_Age = " << st.m_Age << endl;
	//菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义
	cout << "sizeof(st) = " << sizeof(st) << endl;
}

int main()
{
	test01();
}

 三种访问方式得到的都是同一份数据

虚基类的底层实现

vbptr:虚基类指针

Sheep和Tuo类继承的都是vbptr和一个偏移量

今日效率极高,一下午搞定了C++的继承

2023年5月8日

P135 多态的基本语法

无虚函数,执行 Animal is speaking

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

class Animal 
{
public:
	 void speak()
	{
		cout << "Animal is speaking" << endl;
	}
};

class Cat : public Animal
{
public:
	void speak()
	{
		cout << "Cat is speaking" << endl;
	}
};
//地址早绑定 在编译阶段确定函数地址
//如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定
void doSpeak(Animal &animal)
{
	animal.speak();
}

void test01()
{
	Cat cat;
	doSpeak(cat);

}

int main()
{
	test01();
}

有虚函数

执行 Cat is speaking

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

class Animal 
{
public:
	virtual void speak()
	{
		cout << "Animal is speaking" << endl;
	}
};

class Cat : public Animal
{
public:
	void speak()
	{
		cout << "Cat is speaking" << endl;
	}
};
//地址早绑定 在编译阶段确定函数地址
//如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定
void doSpeak(Animal &animal)
{
	animal.speak();
}

void test01()
{
	Cat cat;
	doSpeak(cat);

}

int main()
{
	test01();
}
#include<iostream>
#include<string>
using namespace std;

class Animal 
{
public:
	virtual void speak()
	{
		cout << "Animal is speaking" << endl;
	}
};

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

class Dog : public Animal
{
public:
	void speak()
	{
		cout << "Dog is speaking" << endl;
	}
};
//地址早绑定 在编译阶段确定函数地址
//如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定

//我们希望传入什么对象,那么就调用什么对象的函数
//如果函数地址在编译阶段就能确定,那么静态联编
//如果函数地址在运行阶段才能确定,就是动态联编
void doSpeak(Animal &animal)
{
	animal.speak();
}

//多态满足条件: 
//1、有继承关系
//2、子类重写父类中的虚函数
//多态使用:
//父类指针或引用指向子类对象
void test01()
{
	Cat cat;
	doSpeak(cat);
	Dog dog;
	doSpeak(dog);
}

int main()
{
	test01();
}

总结:

多态满足条件

  • 有继承关系
  • 子类重写父类中的虚函数

多态使用条件

  • 父类指针或引用指向子类对象

重写:函数返回值类型 函数名 参数列表 完全一致称为重写

2023年5月9日

P136 多态的原理剖析

验证虚函数(表)指针

sizeof(Animal)=4

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

class Animal 
{
public:
	virtual void speak()
	{
		cout << "Animal is speaking" << endl;
	}
};

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

class Dog : public Animal
{
public:
	void speak()
	{
		cout << "Dog is speaking" << endl;
	}
};
//地址早绑定 在编译阶段确定函数地址
//如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定

//我们希望传入什么对象,那么就调用什么对象的函数
//如果函数地址在编译阶段就能确定,那么静态联编
//如果函数地址在运行阶段才能确定,就是动态联编
void doSpeak(Animal &animal)
{
	animal.speak();
}

//多态满足条件: 
//1、有继承关系
//2、子类重写父类中的虚函数
//多态使用:
//父类指针或引用指向子类对象
void test01()
{
	Cat cat;
	doSpeak(cat);
	Dog dog;
	doSpeak(dog);
}

void test02()
{
	cout << "sizeof(Animal)" << sizeof(Animal) << endl;
}
int main()
{
	/*test01();*/
	test02();
}

Cat没有重写speak函数时

 Cat重写speak函数时

vfptr指向的函数是@Cat::speak

P137 多态案例1:计算器类

多态的优点:

* 代码组织结构清晰

* 可读性强

* 利于前期和后期的扩展以及维护

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

//普通实现计算器类
	//如果要提供新的运算,需要修改源码
class Calculator
{
public:
	int num1;
	int num2;
	int getRes(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 = 10;
	cout << c.getRes("*") << endl;
	cout << c.getRes("+") << endl;
	cout << c.getRes("-") << endl;
}
//多态实现计算机类
//多态实现
//抽象计算器类
//多态优点:代码组织结构清晰,可读性强,利于前期和后期的扩展以及维护
class AbstractCalculator
{
public:
	int  num1;
	int num2;
	virtual int getRes()
	{
		return 0;
	}
};

class Add :public AbstractCalculator
{
public:
	int getRes()
		{
				return num1 + num2;
         }
};

class Sub :public AbstractCalculator
{
public:
	int getRes()
		{
				return num1 -num2;
		}
};

class Mul :public AbstractCalculator
{
public:
	int getRes()
		{
				return num1 * num2;
		}
};

void test02()
{
	AbstractCalculator *c=new Add;
	c->num1 = 10;
	c->num2 = 10;
	cout << c->getRes() << endl;
	delete c; //用完了记得销毁
     c = new Sub;
	 c->num1 = 10;
	 c->num2 = 10;
	cout << c->getRes() << endl;
	delete c;
	 c = new Mul;
	 c->num1 = 10;
	 c->num2 = 10;
	cout << c->getRes() << endl;
}


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

> 总结:C++开发提倡利用多态设计程序架构,因为多态优点很多

P138 纯虚函数和抽象类

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

class Base
{
public:
	//纯虚函数
	//类中只要有一个纯虚函数就称为抽象类
	//抽象类无法实例化对象
	//子类必须重写父类中的纯虚函数,否则也属于抽象类
	virtual void func() = 0;
};

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

void test01()
{
	Base* base = NULL;
	base = new Son;
	base->func();
	delete base;//记得销毁
}

int main()
{
	test01();
}

P139 多态 案例2 制作饮品

#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 doDrink()
	{
		boil();
		brew();
		pourincup();
		putsomething();
	}
};

class Coffee : public AbstractDrinking
{
public:
	void boil()
	{
		cout << "烧开农夫山泉" << endl;
	};
	void brew()
	{
		cout << "冲泡咖啡" << endl;
	};
	void pourincup()

	{
		cout << "倒入杯中" << endl;
	};
	void putsomething()
	{
		cout << "倒入牛奶和糖" << endl;
	};
};

class Tea : public AbstractDrinking
{
public:
	void boil()
	{
		cout << "烧开矿泉水" << endl;
	};
	void brew()
	{
		cout << "冲泡茶叶" << endl;
	};
	void pourincup()

	{
		cout << "倒入杯中" << endl;
	};
	void putsomething()
	{
		cout << "倒入枸杞" << endl;
	};
};

//业务函数
void dowork(AbstractDrinking* abs)
{
	abs->doDrink();
	delete abs;
}
void test01()
{
	dowork(new Coffee);
	cout << "----------------------------" << endl;
	dowork(new Tea);
}

int main()
{
	test01();
}

2023年5月10日

P140 虚析构与纯虚析构

多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码



 

解决方式:将父类中的析构函数改为**虚析构**或者**纯虚析构**



 

虚析构和纯虚析构共性:

* 可以解决父类指针释放子类对象

* 都需要有具体的函数实现

虚析构和纯虚析构区别:

* 如果是纯虚析构,该类属于抽象类,无法实例化对象

没有虚析构时,不会调用子类的析构函数

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

class Animal
{
public:
	Animal()
	{
		cout << "call of ANIMAL constructor" << endl;
	}
	virtual void speak() = 0;

	~Animal()
	{
		cout << "call of Animal desconstructor" << endl;
	}
};

class Cat : public Animal
{
public:
	void speak()
	{
		cout <<*m_Name<< "Cat is spraking" << endl;
	}

	Cat(string name)
	{
		cout << "call of Cat contructor" << endl;
		m_Name = new string(name);
	}

	string* m_Name;

	~Cat()
	{
		cout << "call of Cat desconstructor" << endl;
		if (m_Name != NULL)
		{
			delete m_Name;
			m_Name = NULL;
		}
	}
};

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

int main()
{
	test01();
}

 父类中析构函数变为虚析构时

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

class Animal
{
public:
	Animal()
	{
		cout << "call of ANIMAL constructor" << endl;
	}
	virtual void speak() = 0;

	virtual ~Animal()
	{
		cout << "call of Animal desconstructor" << endl;
	}
};

class Cat : public Animal
{
public:
	void speak()
	{
		cout <<*m_Name<< "Cat is spraking" << endl;
	}

	Cat(string name)
	{
		cout << "call of Cat contructor" << endl;
		m_Name = new string(name);
	}

	string* m_Name;

	~Cat()
	{
		cout << "call of Cat desconstructor" << endl;
		if (m_Name != NULL)
		{
			delete m_Name;
			m_Name = NULL;
		}
	}
};

void test01()
{
	Animal * animal=new Cat("Tom");
	animal->speak();
	//父类指针在析构时,不会调用子类中的析构函数。如果子类中有堆区属性,会导致内存泄露
	delete animal;
}

int main()
{
	test01();
}

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

class Animal
{
public:
	Animal()
	{
		cout << "call of ANIMAL constructor" << endl;
	}
	virtual void speak() = 0;
	//析构函数加上virtual关键字,变成虚析构函数
	/*virtual ~Animal()
	{
		cout << "call of Animal desconstructor" << endl;
	}*/
	//纯虚析构函数需要声明,也需要实现
	//有了纯虚析构之后,函数也为抽象类
	virtual ~Animal() = 0;
};
//纯虚析构函数需要声明,也需要实现
Animal::~Animal()
{
	cout << "Animal 的纯虚析构函数调用" << endl;
}
class Cat : public Animal
{
public:
	void speak()
	{
		cout <<*m_Name<< "Cat is spraking" << endl;
	}

	Cat(string name)
	{
		cout << "call of Cat contructor" << endl;
		m_Name = new string(name);
	}

	string* m_Name;

	~Cat()
	{
		cout << "call of Cat desconstructor" << endl;
		if (m_Name != NULL)
		{
			delete m_Name;
			m_Name = NULL;
		}
	}
};

void test01()
{
	Animal * animal=new Cat("Tom");
	animal->speak();
	//父类指针在析构时,不会调用子类中的析构函数。如果子类中有堆区属性,会导致内存泄露
	//通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄漏
	//怎么解决?给基类增加一个虚析构函数
	//虚析构函数就是用来解决通过父类指针释放子类对象
	delete animal;
}

int main()
{
	test01();
}

2023年5月11日

P141 电脑组装案例分析

 

 P142 电脑组装具体实现

疑问:

这个案例中为什么Computer类析构时,不需要设置为虚析构函数?
 

#include<iostream>
#include<string>
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 IntelCPU :public CPU
{
	void calculate()
	{
		cout << "IntelCPU is working" << endl;
	}
};

class IntelVideoCard :public VideoCard
{
	void display()
	{
		cout << "IntelVideoCard is working" << endl;
	}
};


class IntelMemory :public Memory
{
	void storage()
	{
		cout << "IntelMemory is working" << endl;
	}
};

class LenovoCPU :public CPU
{
	void calculate()
	{
		cout << "LenovoCPU is working" << endl;
	}
};

class LenovoVideoCard :public VideoCard
{
	void display()
	{
		cout << "LenovoVideoCard is working" << endl;
	}
};


class LenovoMemory :public Memory
{
	void storage()
	{
		cout << "LenovoMemory is working" << endl;
	}
};

class Computer
{
public:
	Computer(CPU*cpu,VideoCard*vc,Memory*me)
	{
		m_cpu = cpu;
		m_vc = vc;
		m_me = me;
	}

	void dowork()
	{
		m_cpu->calculate();
		m_me->storage();
		m_vc->display();
	}
	//老师好,这个案例中为什么Computer类析构时,不需要设置为虚析构函数?

	~Computer()
	{
		cout << "call of Computer desconstructor" << endl;
		if (m_cpu != NULL)
		{
			delete m_cpu;
			m_cpu = NULL;
		}

		if (m_vc != NULL)
		{
			delete m_vc;
			m_vc = NULL;
		}

		if (m_me != NULL)
		{
			delete m_me;
			m_me = NULL;
		}
	}
private:
	CPU* m_cpu;
	VideoCard* m_vc;
	Memory* m_me;
};
//多态的条件:
//父类指针或者引用指向子类
void test01()
{
	//第一台电脑的零件
	CPU *incpu = new IntelCPU;
	VideoCard* invc = new IntelVideoCard;
	Memory* inme = new IntelMemory;
	//组装第一台电脑
	Computer *c1 = new Computer(incpu, invc, inme);
	c1->dowork();
	delete c1;
	cout << "--------------------------------------------" << endl;
	//第二台电脑的零件
	CPU* lecpu = new LenovoCPU;
	VideoCard* levc = new LenovoVideoCard;
	Memory* leme = new LenovoMemory;
	//第二台电脑
	Computer* c2 = new Computer(lecpu, levc, leme);
	c2->dowork();
	delete c2;

}
int main()
{
	test01();
}

2023年5月17日

P 文件操作部分暂时略过

P168 函数模板的基本语法

#include<iostream>
using namespace std;

template <typename T>
void mySwap(T &a, T &b)
{
	T temp = a;
	a = b;
	b = temp;
}

void test01()
{
	int a = 10;
	int b = 20;
	mySwap(a,b);
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
	double c = 10.1;
	double d = 10.2;
	mySwap(c, d);
	cout << "c=" << c << endl;
	cout << "d=" << d << endl;
}

int main()
{
	test01();
}

出现的错误:

调用函数时,没使用变量。而是直接传数字,脑子宕机了

总结

  • 函数模板利用关键字template
  • 使用函数类型模板有两种方式:自动类型推导、显示指定类型
  • 模板的目的是为了提高复用性,将类型参数化

P169 函数模板使用的注意事项

函数模板注意事项

注意事项:

  • 自动类型推导,必须推导出一致的数据类型T才能使用
  • 模板必须要确定出T的数据类型,才可以使用
#include<iostream>
using namespace std;

template <typename T>
void mySwap(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}

void test01()
{
	int a = 10;
	int b = 20;
	char e = 'e';
	mySwap(a, b);//正确
	//自动类型推导,必须推导出一致的数据类型T才能使用
	//mySwap(a, c);
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
	double c = 10.1;
	double d = 10.2;
	mySwap(c, d);
	cout << "c=" << c << endl;
	cout << "d=" << d << endl;
}

//模板必须要确定出T的数据类型,才可以使用
template <class T>
void func()
{
	cout << "world" << endl;

}
void test02()
{
	//func(); //模板必须要确定出T的数据类型,才可以使用
	func<int>();
}
int main()
{
	test01();
	test02();
}

P170 函数模板的案例-数组排序

案例描述:

  • 利用函数模板封装一个排序的函数,可以对不用数据类型数组进行排序
  • 排序规则从大到小,排序算法为选择排序
  • 分别利用char数组和int数组进行测试
#include<iostream>
using namespace std;
//数据交换模板
template <class T>
void mySwap(T& a, T& b)
{
	T temp;
	temp = a;
	a = b;
	b = temp;
}
//数组内容输出模板
template<class T>
void display(T arr[], int len)
{
	int length = len;
	for (int i = 0; i < length; i++)
	{
		cout << arr[i]<<" ";
	}
	cout << " " << endl;
}

template <class T>
void mySort(T arr[],int num)
{
	int length = num;
	int j = 0;
	int max;
	int temp = 0;
	for (int i = 0;i < length; i++)
	{
		max = i;
		for (j = i + 1; j < length; j++)
		{
			if (arr[max] < arr[j])
			{
				max = j;	
			}
			if (max != i)
			{
				mySwap(arr[max], arr[i]);
			}
		}
	}
}

void test01()
{
	char arr[] = "abcedfg";
	int num = sizeof(arr) / sizeof(char);
	mySort(arr, num);
	display(arr, num);
}

void test02()
{
	int arr[] = { 1,2,3,5,6,9 };
	int num = sizeof(arr) / sizeof(int);
	mySort(arr, num);
	display(arr, num);
}
int main()
{
	test01();
	test02();

}

2023年5月21日

P171 1.2.4 普通函数与函数模板的区别

无需特别记录

P172 1.2.5 普通函数与函数模板的调用规则

无需特别记录

P173 1.2.6 模板的局限性

错误:不知道如何解决

#include<iostream>
using namespace std;

class person
{
public:
	string m_name;
	int m_age;
	person(string name,int age)
	{
		m_name = name;
		m_age = age;
	 }
};

 //普通函数模板
//template<class 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)
	{
		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 test01()
{
	person p1("tom", 10);
	person p2("tom", 10);
	bool res = mycompare(p1,p2);
	if (res) { cout << "p1==p2"; }
	else { cout << "p1 != p2 "; }
}

int main()
{
	test01();
}

正确的:(似乎只有重载才行)

#include<iostream>
using namespace std;

class person
{
public:
	string m_name;
	int m_age;
	person(string name,int age)
	{
		m_name = name;
		m_age = age;
	 }
};

 //普通函数模板
template<class 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)
	{
		return true;
	}
	else {
		return false;
	}
}

2023年5月22日

P174 类模板语法

无需特别记录

P175 类模板与函数模板区别

P176 类模板中成员函数创建时机

P177 类模板对象做函数参数

2023年5月24日

P178-P179

P180  类模板分文件编写.cpp中代码

014.CPP

#include<iostream>
using namespace std;
#include<string>
//#include "person.h"
解决方式1,包含cpp源文件
//#include "person.cpp"
//解决方式2,将声明和实现写到一起,文件后缀名改为.hpp
// hpp文件属于头文件 推荐这种
#include "person.hpp"


//template<class t1, class t2>
//class person
//{
//public:
//	person(t1 age, t2 name);
//	void showperson();
//
//	t1 name;
//	t2 age;
//};

//构造函数 类外实现
//template<class t1, class t2>
//person<t1, t2>::person(t1 name, t2 age)
//{
//
//	this->age = age;
//	this->name = name;
//
//}

//成员函数 类外实现
//template<class t1, class t2>
//void person<t1, t2>::showperson()
//{
//	cout << this->name << this->age << endl;
//}
//
void test01()
{
	person<string, int>p1("tom", 18);
	p1.showperson();
}

int main()
{
	test01();
}

第一种解决方法:

person.h

#pragma once
#include<iostream>
using namespace std;
#include<string>

template<class t1, class t2>
class person
{
public:
	person(t1 age, t2 name);
	void showperson();

	t1 name;
	t2 age;
};

person.cpp

#include"person.h"

template<class t1, class t2>
person<t1, t2>::person(t1 name, t2 age)
{

	this->age = age;
	this->name = name;

}

template<class t1, class t2>
void person<t1, t2>::showperson()
{
	cout << this->name << this->age << endl;
}

第二种解决方法:

//解决方式2,将声明和实现写到一起,文件后缀名改为.hpp
// hpp文件属于头文件 推荐这种

person.hpp

#pragma once
#include<iostream>
using namespace std;
#include<string>

template<class t1, class t2>
class person
{
public:
	person(t1 age, t2 name);
	void showperson();

	t1 name;
	t2 age;
};



template<class t1, class t2>
person<t1, t2>::person(t1 name, t2 age)
{

	this->age = age;
	this->name = name;

}

template<class t1, class t2>
void person<t1, t2>::showperson()
{
	cout << this->name << this->age << endl;
}

 2023年5月28日

P186 vector存放内置数据类型

 for_each的底层原理

 

#include<iostream>
#include<vector>
#include<algorithm>//标准算法的头文件
using namespace std;


void print(int value)
{
	cout << value << endl;
}
void test01()
{
	vector<int>v;
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);

	for_each(v.begin(), v.end(), print);
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值