C++学习

C++代码基础结构

手动编译代码并运行

Cout打印输出

数据类型-实型

在编译器中,会将"float = 3.14"中的“3.14”视为一个double类型的数据,再将其转换为float类型,这样就会多一步转换的操作,我们可以直接写成float = 3.14f,这样就省略了转换的操作

科学计数法

字符型

字符型只能使用‘ ’进行创建,用双引号会报错

创建字符型变量时候,单引号内只能有一个字符

\t水平制表符,算上前面的内容一共留下8个字符空间

水平制表(HT)(跳到下一个TAB位置) 

算术运算符

两个小数是不可以做取模运算的,只有整形变量可以进行取模运算

程序的内存模型

new操作符

#include <iostream>
using namespace std;
#include <string.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int* my_fuc()
{
	int* p = new int(10);
	return p;
	
} 


void test1()
{
	int * p = my_fuc();
	
	cout << *p <<endl;
	
	delete p;//内存已经被释放,再次访问就是非法操作,会报错(不一定会报错,但会乱码) 
	cout << *p <<endl;
	
}
//2、在堆区利用new开辟数组
void test2()
{
	//创建10整型数据的数组,在堆区
	int* arr = new int[10];//代表数组有10个元素
	for(int i = 0;i<10;i++)
	{
		arr[i] = i;
	}
	for(int i = 0;i<10;i++)
	{
		cout << arr[i] << endl;
	}
	delete[] arr;
	for(int i = 0;i<10;i++)
	{
		cout << arr[i] << endl;
	}
}

int main(int argc, char** argv) {
	test1();
	
	test2();
	return 0;
}

C++中的引用 

1.引用的基本使用

#include <iostream>
using namespace std;
#include <string.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char** argv) {
	int a = 10;
	int &b = a;
	b = 20;
	cout << a << endl;
	
	return 0;
}

2.引用注意事项

1.引用必须初始化

2.引用在初始化后,不可以改变

#include <iostream>
using namespace std;
#include <string.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char** argv) {
	int a = 10;
	int &b = a;
	int c = 20;
	b= c;
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
	
	
	return 0;
}

3. 引用做函数参数

#include <iostream>
using namespace std;
#include <string.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

void my_fuc(int &a ,int &b)
{
	int temper = a;
	a = b;
	b = temper;
	
}
int main(int argc, char** argv) {
	int a = 10;
	int b = 20;
	my_fuc(a, b);
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	
	
	return 0;
}

通过引用参数产生的效果同按地址传递是一样的。引用的语法更清楚简单 

4.引用做函数返回值

1.不要返回局部变量引用

#include <iostream>
using namespace std;
#include <string.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int& my_fuc()
{
	int a = 10;
	return a;
}
int main(int argc, char** argv) {
	
	int &ret = my_fuc();
	cout << "ret = " << ret << endl;//第一次结果正确,是因为编译器做了保留
	cout << "ret = " << ret << endl;//第二次结果错误,因为a的内存已经释放
	cout << "ret = " << ret << endl;//第三次结果错误,因为a的内存已经释放
	
	
	return 0;
}

2、函数的调用可以作为左值

#include <iostream>
using namespace std;
#include <string.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int& my_fuc()
{
	static int a = 10;//静态变量,存放在全局区,全局区上的数据在程序结束后系统释放
	return a;
}
int main(int argc, char** argv) {
	
	int &ret = my_fuc();
	cout << "ret = " << ret << endl;
	cout << "ret = " << ret << endl;
	cout << "ret = " << ret << endl;
	
	my_fuc() = 1000;//如果函数的返回值是引用,这个函数调用可以作为左值
	cout << "ret = " << ret << endl;
	cout << "ret = " << ret << endl;
	
	
	return 0;
}

5.引用的本质 

用const 修饰后,指针的指向是不可以修改的 ,但指向对象的值可以修改

6.常量引用

#include <iostream>
using namespace std;
#include <string.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

void my_fuc(const int &a)
{
	//a = 1000;不可以进行修改操作,已经被const修饰了 
	cout << "a = " << a << endl;
}

int main(int argc, char** argv) {
	
	
	//常量引用
	//使用场景:用来修饰形参,防止误操作
	//int a = 10;
	
	//int  &ref=10;//引用必须引一块合法的内存空间,比如栈区的数据或者堆区的数据,而字面量(存储在常量区)是不允许直接被引用的 ,因此该行代码错误 
	
	//不过可以加上const来直接引用字面量 
	//const int  &ref=10;
	//加上const之后I编译器将代码优化修改int temp = 10; const int & ref = temp;
	//ref=20;//加入const之后变为只读,不可以修改
	return 0;
}

函数高级

1.函数默认参数 

#include <iostream>
using namespace std;
#include <stdio.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

//1、如果某个位置已经有了默认参数,那么从这个位置往后,从左到右都必须有默认值
//2、如果函数声明有默认参数,函数实现就不能有默认参数,声明和实现只能有一个有默认参数
int fuc(int a = 10,int b = 10);

int fuc(int a,int b)
{	
	return a + b; 
}
int main(int argc, char** argv) {
	cout << fuc() << endl;
	
	return 0;
}

2.函数占位参数 

//占位参数 
占位参数还可以有默认参数
void fuc(int a , int = 10)
{
	cout << "Aekbi" << endl;
}
int main()
{
	fuc(10,1);
	return 0;
} 

3.函数重载

void fuc()
{
	cout << "Akebi" << endl;
}
void fuc(int a)
{
	cout << "Komichi" << endl;
}
void fuc(double a)
{
	cout << "Hobert" << endl;
}
void fuc(double a , int b)
{
	cout << "VVV" << endl;
}


int main()
{
	fuc(3.14,10);	 
	return 0;
}

//函数重载的注意事项
//1、引用作为重载的条件 ,满足参数类型不同的函数重载条件 
void func(int &a)//int&a =10;不合法
{
	cout << "func(int&a)调用" << endl;
}

void func(const int &a)//cohst int &a = 10;合法 
{
	cout << "func(const int &a)调用" << endl;
}


//2、函数重载碰到默认参数,对于func2(10)会出现二义性报错 
void func2(int a ,int b = 10)
{
	cout << "func2(int a ,int b = 10)" << endl;
}
 
void func2(int a)
{
	cout << "func2(int a)" << endl;
}

int main()
{
	int a = 10; 	
	//func(a); //func(int&a)调用
	func(10);//func(const int &a)调用
	
	
	func2(10,20);
	return 0;
}

类和对象

1.封装

#include <iostream>
using namespace std;
#include <stdio.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
const double Pi = 3.14;
class Circle
{
	public:
		int radlus;
		double get_C()
		{
			return 2*Pi*radlus;
		}
};//类的结尾大括号需要加上; 

int main(int argc, char** argv) {
	
	Circle C1;
	C1.radlus = 10;
	cout << "圆的周长" << C1.get_C() << endl; 	
	return 0;
}

2.struct和class区别

3.成员属性设置为私有

class Person
{
	//1、可以自己控制读写权限
	//2、对于写可以检测数据有效性
	private:
		string P_name;//姓名可读可写
		int P_age;//年龄只读也可以写(年龄必须在王 0 到150之间)
		string P_ido;//偶像只写
	public:
		void setname(string name)
		{
			P_name = name;//属性名与函数参数名必须不同 
		}
		string getname()
		{
			
			return P_name;
		}
		void setage(int age)
		{
			if(age< 0 || age>150)
			{
				cout << "输入不符合要求" << endl;
				return; 
			}
			P_age = age;
		}
		void setido(string ido)
		{
			P_ido = ido;
		}
		string getido()
		{
			return P_ido;
		}
	
};

int main()
{
	Person p1;
	p1.setido("Akebi");
	cout << "我推:" << p1.getido() << endl;
	
	p1.setage(20);
	
	p1.setname("Hobert");
	

	return 0;
}

4.设计案例

(1)案例1

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



//----------------------------------------------------------------------------------------------------------------------

class Cube
{
private:
	int m_L;
	int m_W;
	int m_H;
	
public:
	void set_Cube(int L,int W ,int H)
	{
		m_L = L;
		m_W = W;
		m_H = H; 
	}
	int get_L()
	{
		return m_L; 
	}
	int get_W()
	{
		return m_W;
	}
	int get_H()
	{
		return m_H; 
	}
	void  class_isSame(Cube c)
	{
		if(m_L == c.get_L() && m_W == c.get_W() && m_H == c.get_H())
		{
			cout << "两立方体一致" << endl; 
		}
		else
		{
			cout << "两立方体不一致" << endl; 
		}
		
	}	
};

void judge_Cube(Cube &c1 , Cube &c2)//全局函数使用引用传参,可以像指针一样不必单独为形参创建变量 
{
	if (c1.get_L() == c2.get_L() && c1.get_W() == c2.get_W() && c1.get_H() == c2.get_H())
	{
		cout << "两立方体一致" << endl; 
	}
	else
	{
		cout << "两立方体不一致" << endl; 
	}
} 


int main()
{
	
	Cube c1;
	c1.set_Cube(10,10,10);
	
	Cube c2;
	c2.set_Cube(10,10,10);
	
	judge_Cube(c1,c2);
	
	
	return 0;
} 

(2)案例2

main.cpp
#include <iostream>
using namespace std; 
#include "point.h"
#include "Circe.h"
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
void is_Same(Circe c, point p)
{
	int distance = (p.get_X() - c.get_point().get_X()) * (p.get_X() - c.get_point().get_X()) +
	(p.get_Y() - c.get_point().get_Y()) * (p.get_Y() - c.get_point().get_Y());//这里记得加; 
	
	int radius = c.get_R() * c.get_R();
	if(distance > radius)
	{
		cout << "点在圆外" << endl; 
	}
	else if(distance == radius)
	{
		cout << "点在圆上" << endl; 
	}
	else 
	{
		cout << "点在圆内" << endl; 
	}
	
}
int main(int argc, char** argv) {
	Circe c1;
	c1.set_R(10);
	point p1;
	p1.set_X(10);
	p1.set_Y(10);
	point p2;
	p2.set_X(10);
	p2.set_Y(0);
	c1.set_point(p2);
	
	is_Same(c1,p1);
	return 0;
}
point.cpp

#include "point.h"

void point::set_X(int x)
{
	m_x = x;
}
int point::get_X()
{
	return m_x;
}
void point::set_Y(int y)
{
	m_y = y;
}
int point::get_Y()
{
	return m_y;
}
 
point.h
#pragma once
#include <iostream> 
using namespace std;

class point//类名的大小写要确保与后面一致 
{
	public:
		void set_X(int x);
	
		int get_X();
	
		void set_Y(int y);
		
		int get_Y();
		
	private:
		int m_x;
		int m_y;
	
}; 
Circe.cpp

#include "Circe.h"


void Circe::set_R(int r)
{
	m_r = r;
}
int Circe::get_R()
{
	return m_r;
}
void Circe::set_point(point p)
{
	Circe_heart = p;
}
point Circe::get_point()
{
	return Circe_heart;
}
point.h
#pragma once
#include <iostream> 
using namespace std;
#include "point.h"

class Circe
{
	public:
		void set_R(int r);
		
		int get_R();
		
		void set_point(point p);
		
		point get_point();
		
	private:
		int m_r;
		point Circe_heart;
	
};
	

5.对象的初始化和清理 

析构代码,将堆区开辟的数据做释放的操作

class Person
{
	public:
		Person()
		{
			cout << "Akebi" << endl;
		}
		~Person()
		{
			cout << "Komichi" << endl;
		}
	
};
int main(int argc, char** argv) {
	Person p;
	system("pause");
	return 0;
}

6.构造函数的分类及调用 

        

#include <iostream>
using namespace std;


/* run this program using the console pauser or add your own getch, system("pause") or input loop */
class Person
{
	public:
		
		Person()
		{
			cout << "无参" << endl;
		}
		Person(int a)
		{
			age = a;
			cout << "有参" << endl; 
		}
		Person(const Person &p)
		{
			age = p.age;
			cout << "拷贝" << endl; 
		}
		~Person()
		{
			cout << "析构函数" << endl;
		}
		int age;
	
};
void test01()
{
	//1、括号法
	Person p1;//默认构造函数调用
	Person p2(10);//有参构造函数
	Person p3(p2);//拷贝构造函数
	cout << p3.age <<endl;
	
	//注意事项
	//调用默认构造函数时候,不要加()	
	//因为下面这行代码,编译器会认为是一个函数的声明,不会认为在创建对象
	//Person p1()
	
	
	//2、显示法
	Person pl;
	Person p2=Person(10);//有参构造
	Person p3=Person(p2);//拷贝构造
	//Person(10);//等号右边单独提C出来称为匿名对象,特点:当前行执行结束后,系统会立即回收掉匿名对象
	
	
	//注意事项2
	//不要利用拷贝构造函数初始化匿名对象编译器会认为Person(p3)== Person p3;报错重定义 
	//Person(p3) :
	
	
	
	
	//3、隐式转换法
	Person p4 = 10:相当于写了Person p4 = Person(10) ;有参构造
	Person p5 = p4;/拷贝构造
}

int main(int argc, char** argv) {
	test01();
	system("pause");
	return 0;
}

7.拷贝构造函数调用时机 

#include <iostream>
using namespace std;


/* run this program using the console pauser or add your own getch, system("pause") or input loop */
class Person
{
	public:
		
		Person()
		{
			cout << "无参" << endl;
		}
		Person(int a)
		{
			age = a;
			cout << "有参" << endl; 
		}
		Person(const Person &p)
		{
			age = p.age;
			cout << "拷贝" << endl; 
		}
		~Person()
		{
			cout << "析构函数" << endl;
		}
		int age;
	
};

//利用拷贝来初始化一个新对象 
void test01()
{
	Person p1;
	Person p2(p1);
}


//作形参传入时,p为一份拷贝 
void my_fuc(Person p)
{
	cout << "Akebi" << endl; 
}
void test02()
{
	Person p3;
	my_fuc(p3);
}


//作函数返回值时,返回值为p4拷贝值 
Person my_fuc() 
{
	Person p4;
	return p4; 
}
void test03()
{
	Person p5 = my_fuc(); 
}



int main(int argc, char** argv) {
	test01();
	system("pause");
	return 0;
}

8.构造函数调用规则

9.深拷贝与浅拷贝

#include <iostream>
using namespace std;


/* run this program using the console pauser or add your own getch, system("pause") or input loop */
class Person
{
	public:
		
		Person()
		{
			cout << "无参" << endl;
		}
		Person(int a, int b)
		{
			age = a;
			height = new int(b);
			cout << "有参" << endl; 
		}
		Person(const Person &p)
		{
			age = p.age;//编译器默认为浅拷贝 
			height = new int(*p.height);//深拷贝操作 
			cout << "拷贝" << endl;
		}
		
		//堆区创建的数据由程序员手动释放 
		~Person()
		{
			if (height != NULL)
			{
				delete height;
				height = NULL;
			}
			cout << "析构函数" << endl;
		}
		int age;
		int* height; 
	
};

//利用拷贝来初始化一个新对象 
void test01()
{
	Person p1(18,172);
	Person p2(p1);
	cout << "p1的age:" <<  p1.age << endl;
	cout << "p1的height:" <<  *p1.height << endl; 
	cout << "p2的age:" <<  p2.age << endl;
	cout << "p2的height:" <<  *p2.height << endl;
}
int main(int argc, char** argv) {
	test01();
	system("pause");
	return 0;
}

10.初始化列表

class Person
{
	public:
		Person(int a ,int b , int c):m_a(a),m_b(b),m_c(c)
		{
			
		}		
		int m_a;
		int m_b;
		int m_c;
	
};


void test()
{
	
	//Person p(1,2,3);//构造函数要这样调用 ,第一种 
	Person p = Person(10,20,30);//第二种 

	cout << p.m_a << endl;
	cout << p.m_b << endl;
	cout << p.m_c << endl;
}
int main()
{
	test();
	return 0;
}

11.类对象作为类成员

class Phone
{
public:
	Phone(string name):Phonename(name)
	{
		cout << "Phone构造函数" << endl; 
	}
	string Phonename;
};
class Person
{
public:
	Person(string Per_name ,string Pho_name):Person_name(Per_name),P_Phone(Pho_name)
	{
		cout << "Person的构造函数" << endl; 
	}
	string Person_name;
	Phone P_Phone;
	
};
void test()
{
	Person p("Akebi","Komichi");\
	cout << p.Person_name << p.P_Phone.Phonename << endl;
	
}
 
int main()
{
	test();
	return 0;
}

11.静态成员

(1)静态成员变量

在编译阶段分配内存:在还没有运行exe文件之前就分配了内存,分配在全局区

#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
class Person
{
public:
	static int age;//静态变量需要写在public下 ,class的成员变量默认是private的,需要公共权限才可以类外声明 
	//静态成员变量也是有访问权限的
};

int Person::age = 18;//类作用域 

void test01()
{
	
	//静态成员变量不属于某个对象上,所有对象都共享同一份数据
	//因此静态成员变量有两种访问方式
	//1、通过对象进行访问
	Person p1;
	cout << p1.age << endl;
	Person p2;
	p2.age = 20; 
	cout << p1.age << endl; 
	
	
	//2、通过类名进行访问
	cout << Person::age << endl;
	
}
int main(int argc, char** argv) {
	test01();
	
	return 0;
}

(2)静态成员函数

#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
class Person
{
public:
	//静态成员函数也是有访问权限的,外部不可以访问private 
	static my_func()
	{
		age = 22;//静态成员函数可以访问静态成员变量
		//静态成员函数不可以访问非静态成员变量,无法区分到底是哪个对象的成员变量 
	}
	static int age;//静态变量需要写在public下 ,class的成员变量默认是private的,需要公共权限才可以类外声明 
	//静态成员变量也是有访问权限的
};

int Person::age = 18;//类作用域 

void test01()
{

	Person p1;
	cout << p1.age << endl;
	Person p2;
	p2.age = 20; 
	cout << p1.age << endl; 
	
	
	p1.my_func();
	cout << p1.age << endl; 
	cout << p2.age << endl;
	Person::my_func();//直接通过类名访问函数 
	 
	
	cout << Person::age << endl;
	
}
int main(int argc, char** argv) {
	test01();
	
	return 0;
}

12.C++对象模型和this指针

(1)成员变量和成员函数分开存储

class Person
{
	int age;//非静态成员变量属于类的对象上
	static int hei;//静态成员变量不属于类对象上
	void my_func();//非静态成员函数不属于类对象上
	static void funv();//静态成员函数不属于类的对象上
	
};

//void test01()
//{
//	Person p;
//	
//	cout << sizeof(p) << endl;//Person空类大小为1
//}

void test02()
{
	Person p;
	cout << sizeof(p) << endl;//4
}

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

(2)this指针概念

class Person
{
public:
	Person(int age)
	{
		//this指针指向被调用的成员函数所属的对象
		this -> age = age;//这样可以避免成员变量与形参同名导致错误的情况 
	}
	Person& add_age(Person &p)//如果函数的返回值类型不是引用而是Person,则会导致链式编程失败,因为函数每次返回都创建的是新的类对象 
//以引用的方式返回不会创建新的对象,而以值的方式返回则会创建新的对象
	{
		this -> age += p.age;
		return *this; 
		//this指向p2的指针,而*this指向的就是p2这个对象本体
	}
	int age;
};


void test01()
{
	Person p1(18);
	cout << p1.age << endl;
	Person p2(10);
	
	//链式编程
	p1.add_age(p2).add_age(p2);
	cout << p1.age << endl; //这种形式的cout也是一种链式编程
}



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

13.空指针访问成员函数

#include <iostream>
using namespace std;

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

class Person
{
	public:
		void show_class()
		{
			cout << "this is a class" << endl;
		}
		void show_member()
		{
			cout << "age:" << m_age << endl;//在调用成员变量时,实际上形式是:this->m_age, 但此时p为空指针 ,this也是一个空指针 
		}	
		int m_age;
};

void test01()
{
	Person* p = NULL;
	p->show_class();
	p->show_member();//该行代码会报错
}

int main(int argc, char** argv) {
	test01();
	
	
	return 0;
}

14.const修饰成员函数

class Person
{
	public:
		//this指针的本质是指针常量指针的指向是不可以修改的
		//this指针不可以修改指针的指向的
		//在成员函数后面加const,修饰的是this指向,让指针指向的值也不可以修改
		//相当于const Person * const this
		void my_add() const
		{
			//m_age = 10;
			this -> m_b = 30;
		}
		void test()
		{
			
		}
		
		int m_age = 10;
		mutable int m_b = 20; //特殊变量,即使在常函数中,也可以修改这个值,加关键字mutable
};
int main()
{
	//声明常量时需要为其指定一个初始值,要不就将 m_age 和 m_b 赋值,要不实例化对象时写成const Person p = Person(); 
	//不然会报错 
	const Person p;//在对象前加const,变为常对象
	p.my_add();
	p.m_b = 50;//m_B是特殊值,在常对象下也可以修改
	//p.test();//常对象不可以调用普通成员函数,因为普通成员函数可以修改属性
	return 0;
} 

15.友元(这里多看看,有点不太懂)

(1)全局函数做友元

class school 
{
	friend void gay();
	public:
		school()
		{
			school_lou = "楼";
			school_fang = "房"; 
		}
		
	private:
		string school_lou;
		string school_fang;
	
};
void gay()
{
	
	school sc;
	cout << sc.school_lou << endl;
	cout << sc.school_fang << endl;
}
void test01()
{
	gay();
}
int main()
{
	test01();
	return 0;
}

(2)类做友元

class School;

class Gay 
{
	public:
		Gay();
		void visit();
		School* school;
		 
};

class School
{
	friend class Gay; 
	public:
		School()
		{
			school_lou = "楼";
			school_fang = "房"; 
		}
		string school_lou;
	private:
		
		string school_fang;	
};

Gay::Gay()
{
	school = new School;//new School会调用其构造函数 
}

void Gay::visit()
{
	
	cout << school->school_lou << endl;
	cout << school->school_fang << endl;

}

void test01()
{
	Gay gg;
	gg.visit();
}
int main()
{
	test01();
	return 0;
} 

(3)成员函数做友元

class School;

class Gay 
{
	public:
		Gay();
		void visit01();
		void visit02();
		School* school;
		 
};

class School
{
    //告诉编译器Gay类中的visit成员函数是Building好朋友,可以访问私有内容
	friend void Gay::visit01();
	public:
		School()
		{
			school_lou = "楼";
			school_fang = "房"; 
		}
		string school_lou;
	private:
		
		string school_fang;	
};

Gay::Gay()
{
	school = new School;//new School会调用其构造函数 
}

void Gay::visit01()
{
	
	cout << school->school_lou << endl;
	cout << school->school_fang << endl;

}

void Gay::visit02()
{
	
	cout << school->school_lou << endl;
	//cout << school->school_fang << endl;

}

void test01()
{
	Gay gg;
	gg.visit01();
	gg.visit02();
}
int main()
{
	test01();
	return 0;
} 

16.运算符重载

(1)加号运算符重载

(2)左移运算符重载 

cout的数据类型为标准的输出流对象,且全局只能有一个,一次在多处地方使用的话要用引用

(3)递增运算符重载

class My_int
{
	
	public:
		My_int()
		{
			this->m_value = 0;
			
		}
		
		//前置递增重载
		//前置返回值类型必须是引用,这样可以输出打印多次前置++,且始终作用于同一个变量,如:++(++i); 
		
		My_int& operator++()
		{

			this->m_value++;
			return *this;
		}
		
		//后置递增重载
		//为了区分前置和后置函数重载,需要使用占位参数int,只能使用int,使用其他的数据类型会报错 
		//这里返回值不能写成引用,因为这里的temp是局部变量在函数结束后释放堆区内存,再进行调用会报错
		
		My_int operator++(int) 
		{
			
			//先记录当时结果
			
			//后递增
			
			//最后将记录结果做返回
			
			My_int temp = *this;//先将未++的保存起来
			
			m_value++;
			return temp;
		}
		
		int m_value;	
};

void test01()
{
	My_int i;
	++i;
	cout << i.m_value << endl;
	i++; 
	cout << i.m_value << endl;
	
}

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

(4)赋值运算符重载

class Person
{
	public:
		Person(int age)
		{
			m_age = new int(age);
		}
		~Person()
		{
			if (m_age != NULL)
			{
				delete m_age;
				m_age = NULL;
			}
		}
		
		//重载赋值运算符
		Person& operator=(Person &p)
		{
			
			//编译器是提供浅拷贝
			//m_Age = p.m_Age;
			//应该先判断是否有属性在堆区,如果有先释放干净,然后再深拷贝
			if (m_age != NULL)
			{
				delete m_age;
				m_age = NULL; 
			}
			m_age = new int(*p.m_age);//进行深拷贝 
			return *this; 
		}
		int* m_age;
};

void test01()
{
	
	Person p1(18);
	Person p2(20);
	Person p3(25);
	
	p1 = p2 = p3;//这也是一种链式调用,连续赋值操作 
	cout << "p1的年龄:" << *p1.m_age << endl;
	cout << "p2的年龄:" << *p2.m_age << endl;
	cout << "p3的年龄:" << *p3.m_age << endl;
}

int main(int argc, char** argv) {
	
	test01();
	
	return 0;
}

(5)关系运算符重载

class Person
{
	public:
		Person(string name,int age)
		{
			m_age = age;
			m_name = name;
		} 
		
		//重载==号
		bool operator==(Person &p)
		{
			if(m_age == p.m_age && m_name == p.m_name)
			{
				return true;
			}
			else
			{
				return false;
				
			}
		}
		//重载!=号
		bool operator!=(Person &p)
		{
			if(m_age == p.m_age && m_name == p.m_name)
			{
				return false;
			}
			else
			{
				return true;
				
			}
		}
		int m_age;
		string m_name;
};

void test01()
{
	Person p1("Akebi", 14);
	Person p2("Komichi",15);
	if(p1 == p2)
	{
		
		cout << "p1和p2相等" << endl;
	}
	else
	{
		cout << "p1和p2不相等" << endl;
	}
	
	
	if(p1 != p2)
	{
		
		cout << "p1和p2不相等" << endl;
	}
	else
	{
		cout << "p1和p2相等" << endl;
	}
	
}

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

(6)函数调用运算符重载

class My_print
{
	public:
		void operator()(string my_str)
		{
			cout << my_str << endl; 
		}
};

class My_add
{
	public:
		int operator()(int a ,int b)
		{
			return a+b;//这里不能够直接打印a+b的值,会出错 
		}
};


void test01()
{
	My_print my_print;
	//重载()的操作符也称为仿函数,写法不固定 
	my_print("Akebi Komichi");
	
	My_add my_add;
	int ret  =  my_add(100,200); 
	cout << "ret:" << ret << endl; 
	
	//匿名函数对象
	cout << My_add()(10,10) << endl;//类型加上小括号会创建匿名对象 ,特点:当前行执行完了,立即被释放 
}
int main(int argc, char** argv) {
	test01();
	
	return 0;
}

17.继承

(1)继承的基本语法

#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */


//继承的好处:减少重复代码
//语法:class子类:继承方式父类
//子类也称为派生类
//父类也称为基类
class school
{
	public:
		void name()
		{
			cout << "腊梅" << endl;
		}
		void address()
		{
			cout << "mountain" << endl;
		}
}; 

class Akebi:public school
{
	public:
		void show_message()
		{
			cout << "age:" << m_age << endl;
		}
		int m_age = 14;
	
	
};
class Komichi:public school
{
	public:
		void show_message()
		{
			cout << "age:" << m_age << endl;
		}
		int m_age = 14;
		
	
};
void test01()
{
	Akebi akebi;
	akebi.show_message();
	akebi.name();
	akebi.address();
	Komichi komichi;
	komichi.show_message();
	komichi.name();
	komichi.address();
}
int main(int argc, char** argv) {
	test01();
	return 0;
}

(2)继承方式

class Person
{
	public:
		int m_a = 10;
	protected:
		int m_b = 20;
	private:
		int m_c = 30;
};
class son1:public Person
{
	public:
		void my_func()
		{
			cout << m_a << endl;
			cout << m_b << endl;
			//cout << m_c << endl;
		}
		 	
}; 

class son2:protected Person
{
	public:
		void my_func()
		{
			cout << m_a << endl;
			cout << m_b << endl;
			//cout << m_c << endl;
		}	 	
};


class son3:private Person
{
	public:
		void my_func()
		{
			cout << m_a << endl;
			cout << m_b << endl;
			//cout << m_c << endl;
		}
		 	
};

void test01()
{
	son1 s;
	s.my_func();
}

void test02()
{
	son2 s;
	s.my_func();
}

void test03()
{
	son3 s;
	s.my_func();
}

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

(3)继承中的对象模型

class Father
{
	public:
		int m_a;
	protected:
		int m_b;
	private:
		int m_c;
};
class Son:public Father
{
	public:
		int m_d;
}; 
void test01()
{
	
	//16
	//父类中所有非静态成员属性都会被子类继承下去
	//父类中私有成员属性是被编译器给隐藏了,因此是访问不到,但是确实被继承下去了	
	cout << sizeof(Son) <<endl;
}
int main()
{
	test01();
	return 0;
}

(4)继承中构造和析构顺序

class Father
{
	public:
		Father()
		{
			cout << "Father的构造函数" << endl;
		}
		~Father()
		{
			cout << "Father的析构函数" << endl;
		}
	
}; 

class Son:public Father 
{
	public:
		Son()
		{
			cout << "Son的构造函数" << endl;
		}
		~Son()
		{
			cout << "Son的析构函数" << endl;
		}
};
void test01()
{
	Son s1;
}
int main()
{
	test01();
	return 0;
	
}

(5)继承同名成员处理方式

class Father
{
	public:
		Father()
		{
			m_age = 100;			
		}
		void func()
		{
			cout << "Father的func函数" << endl;
		}
		void func(int a)
		{
			cout << "Father的func(int a)函数" << endl;
		}
		int m_age;	
};

class Son:public Father 
{
	public:
		Son()
		{
			m_age = 200;			
		}
		
		void func()
		{
			cout << "Son的func函数" << endl;
		}
		int m_age;	
};

void test01()
{
	Son s;
	cout << s.m_age <<endl;//直接调用调用是子类中的同名成员
	cout << s.Father::m_age << endl;
	
	s.func();
	
	//如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数
	//如果想访问到父类中被隐藏的同名成员函数,需要加作用域
	s.Father::func(10);
	
	s.Father::func();
}

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

(6)继承同名静态成员处理方式

class Father
{
	public:
		static int m_age;
		static void func()
		{
			cout << "Father的函数" << endl; 
		}
};
int Father::m_age = 100;

class Son:public Father
{
	public:
		static int m_age;
		static void func()
		{
			cout << "Son的函数" << endl; 
		}
	
};
int Son::m_age = 200;



void test01()
{
	
	Son s;
	//1、通过对象访问
	cout << "Son的m_age:" << s.m_age << endl;
	cout << "Father的m_age:" << s.Father::m_age << endl;
	//2、通过类名访问
	cout << "Son的m_age:" << Son::m_age << endl;
	//第一个::代表通过类名方式访问第二个::代表访问父类作用域下
	cout << "Father的m_age:" << Son::Father::m_age << endl;
	
	
	s.func();
	//出现同名,子类会隐藏掉父类中所有同名成员函数,需要加作作用域访问
	s.Father::func();
	
}

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

(7)多继承语法

Son s;

sizeof(Son)  <==> sizeof(s)

class Father1
{
	public:
		
		int m_a = 10;
};
class Father2
{
	public:
		
		int m_b = 20;
};

class Son:public Father1,public Father2
{
	public:
		int m_c = 30;
		int m_d = 40;
};
void test01()
{
	//当父类中出现同名成员,需要加作用域区分
	Son s;
	cout << "m_a:" << s.m_a << endl; 
	cout << "m_b:" << s.m_b << endl;
	cout << "m_c:" << s.m_c << endl;
	cout << "m_d:" << s.m_d << endl;
}

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

(8)菱形继承

vbptr:虚基类指针

vbtable:虚基类表

class Animal
{
	public:
		int m_age = 20;
}; 

//利用虚继承解决菱形继承的问题
//继承之前加上关键字virtual变为虚继承
//Animal类称为虚基类
class Sheep :virtual public Animal
{
	
};
class Tuo :virtual public Animal
{
	
};

class SheepTuo : public Sheep,public Tuo
{
	
};

void test01()
{
	SheepTuo st;
	
	st.Sheep::m_age = 30;
	st.Tuo::m_age = 10;
	//当菱形继承,两个父类拥有相同数据,需要加以作用域区分
	cout << "Sheep的age:" << st.Sheep::m_age << endl;
	cout << "Tuo的age:" << st.Tuo::m_age << endl;
}



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

18.多态

(1)多态的基本概念

在C++中,允许父子之间的类型转换(不需要做强制类型转换),父类的引用可以直接指向子类对象

//执行说话的函数
//地址早绑定在编译阶段确定函数地址
//如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定 


//我们希望传入什么对象,那么就调用什么对象的函数
//如果函数地址在编译阶段就能确定,那么静态联编
//如果函数地址在运行阶段才能确定,就是动态联编

//动态多态满足条件
//1、有继承关系
//2、子类重写父类的虚函数

//动态多态使用
//父类的指针或者引用 指向子类对象

class Animal
{
	public:
		virtual void speak()
		{
			cout << "山里有各种各样的声音" << endl;
		}
};

class Cat:public Animal//必须要有继承关系 
{
	public:
		
		//重写函数返回值类型函数名参数列表完全相同
		void speak()
		{
			cout << "这是哈基米" << endl; 
		} 
};
class Show:public Animal
{
	public:
		void speak()
		{
			cout << "这是雪豹" << endl; 
		} 
};

void doSpeak(Animal &animal)
{
	
	animal.speak();
}
void test01()
{
	Cat cat;
	doSpeak(cat); 
	Show show;
	doSpeak(show);
	
}
int main()
{
	test01();
	 
	return 0;
}

类中定义的函数是分开存储的,内存上不属于类,类的大小为1,但加上virtual 后类的大小就变成4了,这4个字节为指针,类的内部多了一个虚函数表指针

(2)多态案例——计算器类

//如果想扩展新的功能,需求修改源码
//在真是开发中中提倡开闭原则
//开闭原则:对扩展进行开发,对修改进行关闭


//实现计算器抽象类
class AbstractComputer
{
	public:
		virtual int getResult()
		{
			return 0;
		}
		int m_a;
		int m_b;
};
class Add:public AbstractComputer
{
	public:
		int getResult()
		{
			
			return m_a + m_b; 
		} 
};
class Minus:public AbstractComputer
{
	public:
		int getResult()
		{
			
			return m_a - m_b; 
		} 
};
class Mul:public AbstractComputer
{
	public:
		int getResult()
		{
			
			return m_a * m_b; 
		} 
};

void test01()
{
	
	//多态使用条件
	//父类指针或者引用指向子类对象
	AbstractComputer *ab;
	ab = new Add;//该行代码就将虚函数进行了覆盖 
	ab->m_a = 10;
	ab->m_b = 20;
	cout << ab->m_a << "+" << ab->m_b << "=" <<  ab->getResult() << endl; 	
	delete ab;//销毁堆区数据 
	
	
	ab = new Minus;//该行代码就将虚函数进行了覆盖 
	ab->m_a = 10;
	ab->m_b = 20;
	cout << ab->m_a << "-" << ab->m_b << "=" <<  ab->getResult() << endl; 	
	delete ab;//销毁堆区数据 
	 
	ab = new Mul;//该行代码就将虚函数进行了覆盖 
	ab->m_a = 10;
	ab->m_b = 20;
	cout << ab->m_a << "*" << ab->m_b << "=" <<  ab->getResult() << endl; 	
	delete ab;//销毁堆区数据 
} 
int main()
{
	test01();
	
	return 0;
}

(3)纯虚函数和抽象类

抽象类无法在栈或堆上实例化对象

class Father
{
	public:
		virtual void func() = 0;	
};


class Son1:public Father
{
	public:
		virtual void func()//2、抽象类的子类必须要重写父类中的纯虚函数,否则也属于抽象类
		{
			cout << "Son1的func()" << endl; 
			
		}	
};

void test01()
{
	Father *ab = new Son1;
	ab->func();
}
int main()
{
	test01();
	return 0;
}

(4)多态案例二-制作饮品

防止堆区数据的内存泄漏,使用完堆区数据后要进行释放

class Abstract
{
	public:
		virtual void Boil() = 0;
		virtual void Brew() = 0;
		virtual void PourInCup() = 0;
		virtual void plus() = 0;
		void makedrink()
		{
			Boil();
			Brew();
			PourInCup();
			plus();		
		}
}; 

class Coffee:public Abstract
{
	public:
		void Boil()
		{
			cout << "倒水" << endl;
		};
		void Brew()
		{
			cout << "冲泡咖啡" << endl;
		};
		void PourInCup()
		{
			cout << "倒入杯中" << endl;
		};
		void plus()
		{
			cout << "加入糖和牛奶" << endl;
		};	
};

class Tea:public Abstract
{
	public:
		void Boil()
		{
			cout << "倒水" << endl;
		};
		void Brew()
		{
			cout << "冲泡茶叶" << endl;
		};
		void PourInCup()
		{
			cout << "倒入杯中" << endl;
		};
		void plus()
		{
			cout << "加入枸杞" << endl;
		};
};

void work(Abstract* ab)
{
	ab->makedrink();
	delete ab;
}

void test01()
{
	work(new Coffee);
	
	work(new Tea);
} 

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

(5)虚析构和纯虚析构

class Father
{
	public:
		Father()
		{
			cout << "Father的构造函数" << endl;
		}
		
		//实现虚析构或纯虚析构目的:解决父类指针无法访问子类析构,无法释放子类中的堆区数据	
	
//		//利用虚析构可以解决父类指针释放子类对象时不干净的问题
//		virtual ~Father()
//		{
//			cout << "Father的析构函数" << endl;
//		}
	
		//虚析构和纯虚析构函数内部都需要一定的函数实现,不然父类内部可能开辟的堆区数据无法被释放 
		
		//纯虚析构需要声明也需要实现
		//有了纯虚析构之后.,这个类也属于抽象类,无法实例化对象
		virtual ~Father() = 0;
		
		virtual void speak() = 0;
};

Father::~Father()
{
	cout << "Father的纯虚析构函数" << endl;
}

class Son:public Father
{
	public:
		Son(string name)
		{
			m_name = new string(name);
 			cout << "Son的构造函数" << endl; 
		}
		~Son()
		{
			
			cout << "Son的析构函数" << endl;
			if(m_name != NULL)
			{
				delete m_name;
				m_name = NULL;
			}
		}
		void speak()
		{
			
			cout << *m_name <<  "是我涝坡" << endl;
		}
		
		string* m_name;
};

void test01()
{
	Father * ab = new Son("Akebi");
	ab->speak();
    //父类指针在析构时候不会调用子类中析构函数,导致子类如果有堆区属性,出现内存泄漏
	delete ab;//需要对堆区数据进行释放
}
 
int main()
{
	test01();
	return 0;
}

(6)多态案例三-电脑组装

//自解
class CPU_Abstract
{
	public:
		virtual void factory() = 0;
		virtual void work() = 0;
};
class Card_Abstract
{
	public:
		virtual void factory() = 0;
		virtual void work() = 0;
};
class Memory_Abstract
{
	public:
		virtual void factory() = 0;
		virtual void work() = 0;
};

class CPU_Intel:public CPU_Abstract
{
	public:
		void factory()
		{
			cout << "Intel工厂生产" << endl;
		}
		void work()
		{
			cout << "CPU烤肉" << endl;
		}	
};

class Card_huashuo:public Card_Abstract
{
	public:
		void factory()
		{
			cout << "华硕工厂生产" << endl;
		}
		void work()
		{
			cout << "显卡风扇开始转了" << endl;
		}	
};

class Memory_caihong:public Memory_Abstract
{
	public:
		void factory()
		{
			cout << "七彩虹工厂生产" << endl;
		}
		void work()
		{
			cout << "内存爆了" << endl;
		}	
};

class Computer
{
	public:
		void print_messages(CPU_Abstract* cpu,Card_Abstract* card,Memory_Abstract* memory)
		{
			cpu->factory();
			card->factory();
			memory->factory();
		} 
		void processing(CPU_Abstract* cpu,Card_Abstract* card,Memory_Abstract* memory)
		{
			cpu->work();
			card->work();
			memory->work();
		}
	
}; 
void test01()
{
	Computer c;
	c.print_messages(new CPU_Intel ,new Card_huashuo ,new Memory_caihong);
	c.processing(new CPU_Intel ,new Card_huashuo ,new Memory_caihong);
}
int main()
{
	test01();
	return 0;
}

19.文件操作

(1)写文件

(2)读文件

void test01()
{
	ofstream ofs;
	ofs.open("test.txt" , ios::out);
	ofs << "Akebi" << endl;
	ofs << "Komichi" << endl;
	ofs.close();
}

void test02()
{
	ifstream ifs;
	ifs.open("test.txt",ios::in);
	if(!ifs.is_open())
	{
		cout << "文件打开失败" << endl;
		return;
	}
	char data[1024];
	//第一种 
//	while(ifs >> data)//当扫描并写入完后,返回False
//	{
//		cout << data << endl;
//	}
	
	//第二种 
//	while(ifs.getline(data,sizeof(data)))
//	{
//		cout << data << endl; 
//	}

	//第三种 
//	string my_str;
//	while(getline(ifs,my_str))//利用全局函数 
//	{
//		cout << my_str << endl;
//	}
	
	//第四种//一个个读出字符 
	char c; 
	while((c = ifs.get()) != EOF)
	{
		cout << c ;
	}
	
	ifs.close();
}
int main(int argc, char** argv) {
	//test01();
	test02();
	return 0;
}

(3)二进制文件

二进制写入文件可以写入自定义数据类型,比如class

class Person
{
	public:
		char name[1024];
		int m_age;
};

void test01()
{
	
	//2、创建流对象
	//ofstreamn ofs("person.txt",ios::out | ios::binary);//可以在创建对象的时候,进行模式选择和文件名写入 
	ofstream ofs;
	ofs.open("Person.txt",ios::binary | ios::out);//也可以使用write进行模式选择和文件名写入
	Person p = {"Akebi Komichi" , 14};
//	p.m_age = 14;
//	p.name = "Akebi";
	ofs.write((const char*)&p,sizeof(Person));
	ofs.close();
} 

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

class Person
{
	public:
		char m_name[1024];
		int m_age;	
};

void test01()
{
	ifstream ifs;
	ifs.open("Person.txt" , ios::in | ios::binary);
	Person p;
	ifs.read((char*)&p , sizeof(Person));
	if(!ifs.is_open())
	{
		cout << "文件打开失败" << endl;
		return;
	}
	cout << p.m_age << endl;
	cout << p.m_name << endl; 
	ifs.close();
}


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

(4)职工管理系统

C++提高编程

一. 模板

(1)函数模板

主要目的是将类型参数化

#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */


//声明一个模板,告诉编译器后面代码中紧跟着的T不要报错,T是一个通用数据类型
template<typename T>

void my_replace(T &a ,T &b)
{
	T temp = a;
	a = b;
	b = temp;	
} 

void test01()
{
	int a = 10;
	int b = 20;
	//利用函数模板交换
	//两种方式使用函数模板
	//1、自动类型推导
//	my_replace(a,b);
	
	//2、显示指定类型
	my_replace<int>(a,b);	
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
}

int main(int argc, char** argv) {
	test01();
	return 0;
}

(2)函数模板注意事项

(3)普通函数与函数模板的区别 

(4)普通函数与函数模板的调用规则

1.函数模版和普通函数的参数,函数名等都 一致,那么调用普通函数

2.my_func<>(a ,b)中,“<>”就是空模版参数列表

4.如果参数传入char ,而普通函数需要int ,那么就不会发生隐式类型转换,而是模版直接自动类型推导

(5)模板的局限性

class Person
{
	public:
		Person(string name,int age)
		{
			this->m_age = age;
			this->m_name = name;
		} 
		string m_name;
		int m_age;
}; 
template<typename T>
bool my_com(T &p1,T &p2)
{
	if(p1 == p2)
	{
		return true;
	}
	else
	{
		return false;
	}
} 


template<> bool my_com(Person &p1,Person &p2)
{
	if(p1.m_age == p2.m_age)
	{
		return true;
	}
	else
	{
		return false;
	}
}

void test01()
{
	Person p1("Akebi",14);
	Person p2("Komichi",14);
	if(my_com(p1,p2))
	{
		cout << "p1 == p2" << endl;
	}
	else
	{
		cout << "p1 != p2" << endl;	
	}
}
int main()
{
	test01();
	return 0;
	
}

(6)类模板

template<class Nametype,class Agetype>
class Person
{
	public:
		Person(Nametype name, Agetype age)
		{
			this->m_age = age;
			this->m_name = name;
		}
		void showinfo()
		{
			cout << "name:" << this->m_name << endl;
			cout << "age:" << this->m_age << endl;
		}
		string m_name;
		int m_age;	
};
void test01()
{
	Person<string,int> p1("Akebi" , 14);
	p1.showinfo();
}

int main(int argc, char** argv) {
	test01();
	
	return 0;
}

(7)类模板与函数模板区别


//类模板在模板参数列表中可以有默认参数
template<class Nametype,class Agetype = int>
class Person
{
	public:
		Person(Nametype name, Agetype age)
		{
			this->m_age = age;
			this->m_name = name;
		}
		void showinfo()
		{
			cout << "name:" << this->m_name << endl;
			cout << "age:" << this->m_age << endl;
		}
		string m_name;
		int m_age;	
};
void test01()
{
	Person<string> p1("Akebi" , 14);
	p1.showinfo();
}

int main(int argc, char** argv) {
	test01();
	
	return 0;
}

(8)类模板中成员函数创建时机

template<class T>
class my_class
{
public:
	T obj;
	
	//类模版中的成员函数,是在调用的时候才进行创建 
	void my_func01()
	{
		obj.showPerson1();
	}
	void my_func02()
	{
		obj.showPerson2();
	}
	
};


class Person1
{
	public:
		void showPerson1()
		{
			cout << "show Person1" << endl;
		}
};


class Person2
{
	public:
		void showPerson2()
		{
			cout << "show Person2" << endl;
		}
};

void test01()
{
	my_class<Person2> p1;
//	p1.my_func01();
	p1.my_func02();
}

int main(int argc, char** argv) {
	test01();
	
	return 0;
}

(9)类模板对象做函数参数


template<class T1,class T2> 
class Person
{
	public:
		Person(T1 name,T2 age)
		{
			this->m_age  = age;
			this->m_name = name;		
		}
		void showPerson()
		{
			cout << "name: " << m_name << endl;
			cout << "age: "  << m_age << endl;
		}
		T1 m_name;
		T2 m_age;	
};


//类模板对象做函数参数
void my_print1(Person<string,int> &p)
{
	p.showPerson();
	
}

//2、参数模板化
template<class T1,class T2>
void my_print2(Person<T1,T2> &p)
{
	p.showPerson();
	cout << "T1的类型:" << typeid(T1).name() << endl; //使用这个必须包含头文件#include <typeinfo>  
	cout << "T2的类型:" << typeid(T2).name() << endl;
}

//3、整个类模板化
template<class T>
void my_print3(T &p)
{
	p.showPerson();
	
	cout << "T的类型:" << typeid(T).name() << endl;
}

void test01()
{
	Person<string,int>p1("Akebi",14);
	my_print1(p1);
}

void test02()
{
	Person<string,int>p1("Komichi",15);
	my_print2(p1);
}

void test03()
{
	Person<string,int>p1("Hobert",21);
	my_print3(p1);
}

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

(10)类模板分文件编写

类模版一开始是不会创建的,所以仅仅引用.h 文件不行,编译器无法得到.cpp文件中函数的具体实现

类模版的成员函数的创建时机是在调用的时候

//main.cpp

#include <iostream>

using namespace std;

#include "person.hpp"

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

void test01()
{
	Person<string,int> P1("Akebi",14);
	P1.showPerson();
}

int main(int argc, char** argv) {
	
	test01();
	return 0;
}
//person.hpp



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)
{
	
	this->m_Name = name;
	this->m_Age = age;
	
}


template<class T1,class T2> 
void Person<T1,T2>::showPerson()
{
	cout << "Name:" << this->m_Name << endl;
	cout << "Age:" << this->m_Age << endl;
	 
}

(11)类模板与友元

(12)类模板案例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值