c++(都给我用手敲!!!)part two

目录

(一)内存分区模型

(二)new操作符

(三)引用

 (四)函数高级

(五)类和对象

(六)封装属性private protected public

(七)struct和class的区别:默认访问权限不同

(八)成员属性私有化

例一:立方体类

例二:点和圆的关系

(九)构造函数和析构函数

1.定义以及特点

2.构造函数的分类与调用

3.拷贝构造函数的调用时机

4.构造函数的调用规则

5.深拷贝与浅拷贝

(十)初始化列表

(十一)类对象作为类成员

(十二)静态成员


(一)内存分区模型

程序运行前:

(1)代码区  储存缩写代码(二进制);特点:共享和只读

(2)全局区 储存全局变量、静态变量以及常量(其中包含字符串常量和const修饰的全局变量)

程序运行后:

#include<iostream>
using namespace std;
//  g-global(全局变量)  s-stastic(静态变量)   l-local(局部变量) c-const(const修饰的常量)

//全局变量
int g_a = 10;  
int g_b = 20;
//静态变量
static int s_a = 10;
static int s_b = 20;
//全局常量
const int c_g_a = 10;
const int c_g_b = 20;

int main()
{
	//局部变量
	int c = 10;
	int d = 20;
	//局部常量
	const int c_l_a = 10;
	const int c_l_b = 20;
	cout << "全局变量g_a:" << (int) & g_a << endl;
	cout << "全局变量g_b:" << (int) & g_b << endl;
	cout << "局部变量c:" << (int) & c << endl;
	cout << "局部变量d:" << (int) & d << endl;
	cout << "静态变量s_a :" << (int) & s_a << endl;
	cout << "静态变量s_b:" << (int) & s_b << endl;
	cout << "全局常量c_g_a:" << (int) & c_g_a << endl;
	cout << "全局常量c_g_b:" << (int) & c_g_b << endl;
	cout << "局部常量c_g_a:" << (int) & c_l_a << endl;
	cout << "局部常量c_g_b:" << (int) & c_l_b << endl;
	cout << "字符串常量:" << (int)&"hello world" << endl;
	system("pause");
	return 0;
}

/*输出结果:
全局变量g_a:-1521033216
全局变量g_b:-1521033212
局部变量c:-1418004028
局部变量d:-1418003996
静态变量s_a :-1521033208
静态变量s_b:-1521033204
全局常量c_g_a:-1521046608
全局常量c_g_b:-1521046604
局部常量c_g_a:-1418003964
局部常量c_g_b:-1418003932
请按任意键继续. . .
*/

//从分布地址可以以看出:全局变量、静态变量、字符串常量以及全局常量分布在全局区中

(3)栈区 由编译器自动分配和释放

#include<iostream>
using namespace std;
int* func() {
	/*局部变量:存放在栈区,函数运行之后该位置就被释放了,返回地址的话会报错或者返回一个错误的数据;因此不要返回局部变量的地址*/
	int a = 10; 
	return &a;//实在要返回,用malloc函数开辟到堆区就行
}
int main()
{
	int* p = func();    //接受func的返回值:&a

	cout << *p << endl;
	cout << *p << endl;

	system("pause");
	return 0;
}
//vs2022没有发生变化的,是因为stack后续没有发生其他的内存占用,短时间内stack保留了这个数据,你在函数内部写复杂点,多定义几个局部变量,就会和老师的一样了。
/*
输出结果:
10
10
请按任意键继续. . .*/

(4)堆区 由程序员分配和释放 程序员不释放 则由操作系统进行回收

#include<iostream>
using namespace std;
//堆区数据由程序员操作和释放
int* func()
{
	//利用new关键字,将内存开辟到堆区
	int* p = new int(10);   //新开辟一个存放10的整形数据内存空间。用指针p去接收它;
	return p;//返回的是p,不是&p,而p里面的值是指向处于堆区的地址的,堆区不会因为函数的结束而释放,所以是可以的
}//注意:指针本质上是属于栈区的,也是局部变量;但指针中保存的数据属于堆区
int main()
{
	//在堆区开辟数据
	int* p = func();
	cout << *p << endl;
	system("pause");
	return 0;
}
/*输出结果:
* 10
请按任意键继续. . .
*/

/*总结:
1.堆区数据由程序员操作和释放
2.利用new关键字,将内存开辟到堆区
3.栈区中的指针存放的是 堆区中所保留具体数据 在堆区中的地址,所以通过解引用,我们通过指针能得到堆区中的具体数值*/

(二)new操作符

#include<iostream>
using namespace std;
//new操作符
int* func()
{
	int * p = new int(10);       //在堆区开辟一个整型数据10,用指针p去接收它
	return p;                    //返回的是该类型的指针
}
void test01()
{
	int* p = func();              
	cout << *p << endl;        
	cout << *p << endl;
	cout << *p << endl;
	cout << *p << endl;
	//堆区数据由程序员开辟,程序员管理和释放
	//如果想释放堆区数据,使用delete关键字
	delete p;
	//cout << *p << endl;    这块内存已经被释放,再次访问就是非法操作,会报错
}
//在堆区开辟数组
void test02()
{
	int* arr = new int[10];//开辟一个长度为10的整型数组
	for (int i = 0; i < 10; i++)
	{
		arr[i] = i + 100;  //给数组中的每一个数据赋值
    }
	for (int i = 0; i < 10; i++)
	{
		cout << arr[i] << endl;//进行打印操作
	}
	//在释放数组时,需要加[]
	delete[]arr;
}
int main()
{
	test01;
	test02();
	system("pause");
	return 0;
}
/*输出结果:
100
101
102
103
104
105
106
107
108
109
请按任意键继续. . .*/

(三)引用

1.引用的基本语法:数据类型 & 别名 = 原名

#include<iostream>
using namespace std;
int main()
{
	int a = 10;
	int& b = a;     //编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间.
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
	b = 20;
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
	system("pause");
	return 0;
}
/*输出结果:
a=10
b=10
a=20
b=20
请按任意键继续. . .
*/

2.引用的注意事项

#include<iostream>
using namespace std;

int main()
{
	int a = 10;
	//1.引用必须先初始化
	//int& b;//是错误的
 	int& b = a;
	//2.引用一旦在初始化后就不可以再改变
	int& c = a;
	c = b; //这是赋值操作,不是更改引用
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
	cout << "c=" << c << endl;
	system("pause");
	return 0;
}
/*输出结果:
a=10
b=10
c=10
请按任意键继续. . .*/

3.引用做函数参数

#include<iostream>
using namespace std;
//引用做函数参数

//1.值传递:形参不会修饰实参
void myswap01(int a, int b)
{
	int temp = a;
	a = b;
	b = temp;
	cout << "值传递中形参a=" << a << endl;
	cout << "值传递中形参b=" << b << endl;
	cout << endl;
}

//2.地址传递:形参会修饰实参
void myswap02(int* a, int* b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
	cout << "地址传递中形参a=" << *a << endl;
	cout << "地址传递中形参b=" << *b << endl;
	cout << endl;
}

//3.引用传递:形参会修饰实参
void myswap03(int &a,int &b)  //这里&a为下面a的别名;&b为下面b的一个别名
{
	int temp = a;
	a = b;
	b = temp;
	cout << "引用传递中形参a=" << a << endl;
	cout << "引用传递中形参b=" << b << endl;
	cout << endl;
}


int main()
{
	int a = 10;
	int b = 20;
	myswap01(a, b);
	cout << "值传递中实参a=" << a << endl;
	cout << "值传递中实参b=" << b << endl;
	cout << endl;

	myswap02(&a,& b);
	cout << "地址传递中实参a=" << a << endl;
	cout << "地址传递中实参b=" << b << endl;
	cout << endl;

	myswap03(a, b);
	cout << "引用传递中实参a=" << a << endl;
	cout << "引用传递中实参b=" << b << endl;
	cout << endl;
	system("pause");
	return 0;
}
/*输出结果:
* 值传递中形参a=20
值传递中形参b=10

值传递中实参a=10
值传递中实参b=20

地址传递中形参a=20
地址传递中形参b=10

地址传递中实参a=20
地址传递中实参b=10

引用传递中形参a=10
引用传递中形参b=20

引用传递中实参a=10
引用传递中实参b=20

请按任意键继续. . .
*/

4.引用做函数返回值

#include<iostream>
using namespace std;
int& test01()
{
	int a = 10;
	return a;
}
int& test02()
{
	static int a = 10;
	return a;
}
    //注意事项1.不要返回局部变量的引用
int main()
{
	int& ref01 = test01(); //此时ref是a变量的别名
	//cout << "ref01=" << ref01 << endl;     //局部变量储存在栈区,运行之后就会被释放,不要返回局部变量的地址,该操作非法
	int& ref02 = test02();      
	cout << "ref02=" << ref02 << endl;
	cout << "ref02=" << ref02 << endl;
	test02() = 1000;          	//注意事项2:函数的调用可以作为左值
	cout << "ref02=" << ref02 << endl;
	cout << "ref02=" << ref02 << endl;
	system("pause");
	return 0;
}
/*输出结果:
ref02=10
ref02=10
ref02=1000
ref02=1000
请按任意键继续. . .
*/

//如果函数的返回值是引用,那这个函数调用可以作为左值

5.引用的本质:是一个指针常量

#include<iostream>
using namespace std;
void func(int& ref)
{
	ref = 100;
}
//指针常量
int main()
{
	int a = 10;
	int& ref = a;//编译器会自动将这行代码转换为: int * const ref = &a;
	//指针常量是指针指向不可更改,这也说明了为什么引用不可更改
	ref = 20;
	cout << "a=" << a << endl;
	cout << "ref=" << ref << endl;
	func(a);
	system("pause");
	return 0;
}
/*
输出结果:
a=20
ref=20
请按任意键继续. . .*/

6.常量引用

#include<iostream>
using namespace std;
//常量引用:使用场景:修饰形参,防止误操作
int main()
{
	int a = 10;
	int& ref = a;//合法引用,是正确的
	//int& ref = 10; //非法引用,是错误的,右边不能等于常量,得是一块合法的运行空间
	const int& ref = 10;//相当于int temp = 10; const int &ref = temp(创建一个临时变量temp,起一个别名ref去接收它)
	//加入const 之后,变为只读,不可修改
	system("pause");
	return 0;
}
#include<iostream>
using namespace std;
void showvalue01(int& val)
{
	 val = 1000;
	cout << "val=" << val << endl;
}

void showvalue02(const int& val)                        //2.使用引用传递,给m起一个别名val;此时val为常量引用,不可修改,一旦修改就会报错,所以是防止误操作
{
	//val = 1000;   左边必须是可修改的左值,一旦运行就会报错
	cout << "val=" << val << endl;
}

int main()
{
	//常量引用:使用场景:修饰形参,防止误操作
	int a = 100;
	showvalue01(a);
	cout << "a=" << a << endl;

	int m = 20;
	showvalue02(m);                                       //1.定义一个实参m值为20;将m传入
	cout << "m=" << m << endl;
	system("pause");
	return 0;
}
/*输出结果:
val=1000
a=1000
val=20
m=20
请按任意键继续. . .
*/

 (四)函数高级

1.函数的默认参数

语法格式:返回值类型 函数名(形参 = 默认值){}

//#include<iostream>
//using namespace std;
//int func(int a , int b = 20, int c =50) //当函数带有默认值时,只给没有默认值的变量传值是可以的,运行的时候会自动调用默认值
//{
//	cout << "a + b + c =" <<a + b + c << endl;
//	return a + b + c;
//}
//int main()
//{
//	func(10);
//	system("pause");
//	return 0;
//}
///*
//输出结果:
//a + b + c =80
//请按任意键继续. . .*/


#include<iostream>
using namespace std;
int func(int a, int b = 20, int c = 50) 
{
	cout << "a + b + c =" << a + b + c << endl;
	return a + b + c;
}

int main()
{
	func(10,20,30);//当我们传入了数据,就用我们自己的数据,如果没有就调用默认值
	system("pause");
	return 0;
}
/*
输出结果:
a + b + c =60
请按任意键继续. . .
*/

/*注意事项:
1.如果某个位置已经有了默认参数,那么这个位置往后都要有默认值
2.如果函数声明有了默认参数,那么函数的实现就不能有默认参数*/
/*函数声明: int func02(int a =20,int b = 10);
 *函数实现:
 *  int func02(int a =20,int b = 10)       这样定义是错误的,声明和实现不能同时定义默认值        
 * {
 * return a+b;
 * }
*/

2.函数的占位参数

语法格式:返回值类型 函数名 (数据类型){}

注意:占位参数也可以有默认值

#include<iostream>
using namespace std;
void func(int a,int)
{
	cout << "this is function" << endl;
}

void func02(int a = 10, int = 10)
{
	cout << "this is function" << endl;
}
int main()
{
	func(10,10);     //后面这个10也必须要传,否则就会报错
	func02();       /*注意:占位参数也可以有默认值*/
	system("pause");
	return 0;
}
/*输出结果:
this is function
this is function
请按任意键继续. . .*/

3.函数重载

满足条件:1.同一个作用域下    2.函数名称相同  3.函数参数类型不同 或个数不同 或顺序不同

注意:返回值不可以作为函数重载的条件

#include<iostream>
using namespace std;
//函数重载
	//可以让函数名相同,,提高代码的复用度
/*函数重载需要满足的三个条件:1.同一个作用域下    2.函数名称相同  3.函数参数类型不同 或个数不同 或顺序不同*/
void func()
{
	cout << "func()的调用" << endl;
}
void func(int a)
{
	cout << "func(int a)的调用" << endl;
}
void func(double a)
{
	cout << "func(double a)的调用" << endl;
}
void func(int a,double b)
{
	cout << "func(int a,double b)的调用" << endl;
}
void func(double a,int b)
{
	cout << "func(double a,int b)的调用" << endl;
}
//返回值不能作为函数重载的条件, 这样定义是错误的
//int func(double a, int b)
//{
//	cout << "this is function" << endl;
//}      

//注意事项1.引用可以作为函数重载的条件
void func01(int & a)
{
	cout << "func(int & a)的调用" << endl;
}

void func01(const int & a)        //const int& a = 10;合法
{
	cout << " func(const int & a)的调用" << endl;
}
//当函数重载碰到默认参数,出现二义性,应该尽量避免
//void fun02(int a,int b =10)
//{
//	cout << "  fun02(int a,int b =10)的调用" << endl;
//}
//void fun02(int a, int b = 10)
//{
//	cout << "  fun02(int a,int b =10)的调用" << endl;
//}

int main()
{
	func();
	func(10);
	func(3.14);
	func(10, 3.14);
	func(3.14, 10);
	int a = 10;
	func01(a);
	func01(10);
	//func02(10); //此时传一个10进去,func02的两个函数都能调用,系统不知道调用那一个,因此会报错
	system("pause");
	return 0;
}

/*输出结果:
func()的调用
func(int a)的调用
func(double a)的调用
func(int a,double b)的调用
func(double a,int b)的调用
func(int & a)的调用
 func(const int & a)的调用
请按任意键继续. . .
*/

(五)类和对象

三大特性:封装 继承 多态

例一:圆类

#include<iostream>
using namespace std;
const double PI = 3.14;
//定义一个圆类
class circle
{
public:
	int m_r;//定义半径属性
	double calculateCZ()//定义计算圆周长的函数
	{
		return 2 * PI * m_r;//返回计算出来的函数值
	}
};
int main()
{
	//实例化:通过一个类创建一个对象的过程
	circle c1;//实例化一个圆
	c1.m_r = 10;//将该圆的半径赋值为10
	cout <<"圆的周长为:"<< c1.calculateCZ() << endl;//输出圆的周长
	system("pause");
	return 0;
}
/*输出结果:
圆的周长为:62.8
请按任意键继续. . .*/

例二:学生类

#include<iostream>
using namespace std;
//设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓名和学号
class student
{
	//属性: 属性 变量
public:
	//创建属性为姓名、学号
	string name;
	int id;
	//行为:方法 函数
	//显示信息函数
	void showMenu()
	{
		cout << "该生名字为:" << name << endl;
		cout << "该生id为;" << id << endl;
    }
	//输入姓名函数:通过行为给变量赋值
	void setName(string name1)
	{
		name = name1;
	}
	//输入id函数
	void setId(int id1)
	{
		id = id1;
	}
};

int main()
{
	student stu1;
	stu1.name = "张三";
	stu1.id = 6022198056;
	stu1.showMenu();
	student stu2;
	stu2.setName("李四");
	stu2.setId(2037847810);
	stu2.showMenu();
	system("pause");
	return 0;
}
/*输出结果:
该生名字为:张三
该生id为;1727230760
该生名字为:李四
该生id为;2037847810
请按任意键继续. . .
*/

(六)封装属性private protected public

#include<iostream>
using namespace std;
class person
{
private://私有属性:类内可以访问,类外不可以访问;在父类继承中,子类无法访问
	int m_password;
protected://保护属性:类内可以访问,类外不可以访问;在父类继承中,子类可以访问
	string m_car;
public://共有属性:类内类外都可以访问
	string m_name;

public: //当该函数为prpivate时,同样无法执行func操作
	void func()
	{
		m_name = "张三";
		m_car = "拖拉机";
		m_password = 12306;
		cout << m_name << endl;
		cout << m_car << endl;
		cout << m_password << endl;

	}
};
int main()
{
	person p1;
	p1.m_name = "老五";
	cout << p1.m_name << endl;
	/*以下两行代码显示成员不可访问
	p1.m_car = "奔驰";
	p1.m_password = 123456;*/
	p1.func();
	system("pause");
	return 0;
}

/*输出结果:
拖拉机
张三
12306
请按任意键继续. . .
*/

(七)struct和class的区别:默认访问权限不同

struct:默认访问权限为公有

class:默认访问权限为私有

#include<iostream>
using namespace std;
//class和struct区别
class C1
{
	int m;
};

struct C2
{
	int m;
};
int main()
{
	//C1 c1;
	//c1.m = 10;  //class默认属性为private,在类外调用会报错
	C2 c2;
	c2.m = 10;//struct默认属性为public,在类外可以调用
	system("pause");
	return 0;
}

(八)成员属性私有化

#include<iostream>
#include<string>
using namespace std;
class person
{
private:
	string m_name;//可读可写
	int m_age;//只读
	string m_lover;//只写
public:
	//设置姓名
	void setname(string name)
	{
		m_name = name;
	};
	//获取姓名
	string getname()
	{
		return m_name;
	};
	//获取年龄
	int getage( )
	{
		m_age = 200;
		if (m_age < 0 || m_age > 150)
		{
			m_age = 0;
			cout << "你这个老妖精!" << endl;
			return 0;
		}
		return m_age;
	}

	//设置情人
	void setlover(string lover)
	{
		m_lover = lover;
	}
};
int main()
{
	person p1;
	p1.setname("张三");
	cout << "姓名:" << p1.getname() << endl;
	cout << "年龄:" << p1.getage() << endl;
	p1.setlover("苍井");
	system("pause");
	return 0;
}
/*输出结果:
姓名:张三
你这个老妖精!
年龄:0
请按任意键继续. . .
*/

例一:立方体类

#include<iostream>
#include<string>
using namespace std;
//创建一个立方体类:求出立方体面积以及体积,使用全局函数以及成员函数判断两个立方体是否相等
class cube
{
	//属性
private:
	int m_l;//长
	int m_w;//宽
	int m_h;//高
	//行为:函数

public:
	//获取立方体的长宽高
	void setl(int l)
	{
		m_l = l;
	}
	int getl()
	{
		return m_l;
	}
	void setw(int w)
	{
		m_w = w;
	}
	int getw()
	{
		return m_w;
	}
	void seth(int h)
	{
		m_h = h;
	}
	int geth()
	{
		return m_h;
	}

	//求取体积
	int getlf()
	{
		return m_l * m_w * m_h;
	}
	//求取面积
	int getpf()
	{
		return 2 * m_l * m_w + 2 * m_l * m_h + 2 * m_w * m_h;
	}
	//利用成员函数判断两个立方体是否相等
	bool  issameByclass(cube& c)
	{
		if (m_l == c.getl() && m_w == c.getw() && m_h == c.geth())
		{
			return true;
		}
		return false;
	}
};

bool isSame(cube& c1, cube& c2)
{
	if (c1.getl() == c2.getl() && c1.getw() == c2.getw() && c1.geth() == c2.geth())
	{
		return true;
	}
	return false;
}

int main()
{
	cube c1;
	c1.setl(10);
	c1.setw(10);
	c1.seth(10);
	cout << "c1的面积为:" << c1.getpf() << endl;
	cout << "c1的体积为:" << c1.getlf() << endl;
	cube c2;
	c2.setl(11);
	c2.setw(11);
	c2.seth(10);
	cout << "c2的面积为:" << c2.getpf() << endl;
	cout << "c2的体积为:" << c2.getlf() << endl;
	//全局函数需要传两个参数
	bool ret = isSame(c1,c2);
	if (ret)
	{
		cout << "由全局函数判断是相等的" << endl;
	}
	else
	{
		cout << "由全局函数判断是不相等的" << endl;
	}
	//成员函数只要传一个参数
	ret = c1.issameByclass(c2);
	if (ret)
	{
		cout << "由成员函数判断是相等的" << endl;
	}
	else
	{
		cout << "由成员函数判断是不相等的" << endl;
	}
	system("pause");
	return 0;
}

/*
* 测试数据一:c1(10,10,10)  c2(10,10,10)
* 输出结果:
c1的面积为:600
c1的体积为:1000
c2的面积为:600
c2的体积为:1000
由全局函数判断是相等的
由成员函数判断是相等的
请按任意键继续. . .

输出结果:
测试数据二:c1(10,10,10)  c2(11,11,10)
c1的面积为:600
c1的体积为:1000
c2的面积为:682
c2的体积为:1210
由全局函数判断是不相等的
由成员函数判断是不相等的
请按任意键继续. . .
*/

例二:点和圆的关系

//#include<iostream>
//using namespace std;
定义一个圆类
//class Circle
//{
//private:
//	int m_r;
//	int x1;
//	int y1;
//	int x2;
//	int y2;
//public:
//	void setM_r(int r)
//	{
//		m_r = r;
//	}
//	int getM_r()
//	{
//		return m_r;
//	}
//	//获取圆心坐标
//	void setCX(int x)
//	{
//		x1 = x;
//	}
//	int getCX()
//	{
//		return x1;
//	}
//	void setCY(int y)
//	{
//		y1 = y;
//	}
//	int getCY()
//	{
//		return y1;
//	}
//	//获取随机一点
//	void setPX(int x)
//	{
//		x2 = x;
//	}
//	int getPX()
//	{
//		return x2;
//	}
//	void setPY(int y)
//	{
//		y2 = y;
//	}
//	int getPY()
//	{
//		return y2;
//	}
//	int calculateDistance()
//	{
//		return (getCX() - getPX()) * (getCX() - getPX()) + (getCY() - getPY()) * (getCY() - getPY());
//	}
//	int calculateR()
//	{
//		return m_r * m_r;
//	}
//};
//
//int main()
//{
//	Circle c1;
//	c1.setM_r (3);
//	c1.setCX(10);
//	c1.setCY(8);
//	c1.setPX(9);
//	c1.setPY(5);
//	cout << "该圆半径为:"<<c1.getM_r() << endl;
//	cout << "圆心坐标为:"<< c1.getCX()<<"," << c1.getCY() << endl;
//	cout << "随意取一点坐标为:" << c1.getPX()<<"," << c1.getPY() << endl;
//	int dist = c1.calculateDistance();
//	int r = c1.calculateR();
//	if (dist > r)
//	{
//		cout << "点在圆外" << endl;
//	}
//	else if (dist < r)
//	{
//		cout << "点在圆内" << endl;
//	}
//	else
//	{
//		cout << "点在圆上" << endl;
//	}
//	system("pause");
//	return 0;
//}
void point::setX(int x);    告知系统这是point作用域下的成员函数;
在一个类中,可以让另一个类作为本类成员
///*
//输出结果:
//该圆半径为:3
//圆心坐标为:10,8
//随意取一点坐标为:9,5
//点在圆外
//请按任意键继续. . .*/


//改进:在一个类中,将另一个类作为其成员
#include<iostream>
using namespace std;
//创建一个点类
class Point
{
private:
	int	p_x ;
	int p_y ;
public:
	//获取x坐标
	void setP_x(int x)
	{
		p_x = x;
	}
	int getP_x()
	{
		return p_x;
	}
	//获取y坐标
	void setP_y(int y)
	{
		p_y = y;
	}
	int getP_y()
	{
		return p_y;
	}
};
//创建一个圆类
class Circle
{
private:
	int m_r;
	Point m_center; //它的圆心是一个坐标型;point类是不存在的,需要你自己去定义
public:
	/*获取半径*/
	void setm_r(int r)
	{
		m_r = r;
	}
	int getm_r()
	{
		return m_r;
	}
	void setCenter(Point center)   //这个时候point center已经是一个坐标型,只需要给m_center赋值就可以了
	{
		m_center = center;
	}
	Point getCenter()      //传回去一个point的值,返回值类型就要用point;
	{
		return m_center;
	}
};
//利用全局函数判断点和圆之间的关系
void IsInCircle(Circle &c,Point &p)  //全局函数就是要传两个参数
{
	//计算两点之间的距离
	int distance = (c.getCenter().getP_x() - p.getP_x()) * (c.getCenter().getP_x() - p.getP_x())
		+ (c.getCenter().getP_y() - p.getP_y()) * (c.getCenter().getP_y() - p.getP_y());
	//计算半径的平方(根号不好算 所以等式两边平方)
	int rdistance = c.getm_r() * c.getm_r();

	if (distance > rdistance)
			{
				cout << "点在圆外" << endl;
			}
			else if (distance < rdistance)
			{
				cout << "点在圆内" << endl;
			}
			else
			{
				cout << "点在圆上" << endl;
			}
}

int main()
{
	//实例化一个圆c
	Circle c;
	//该圆半径为10
	c.setm_r(10);
	//设置该圆圆心
	Point m_center;
	m_center.setP_x(10);
	m_center.setP_y(0);

	//实例化一个点
	Point p;
	p.setP_x(10);
	p.setP_y(9);

	//判断圆与点的位置关系
	IsInCircle(c, p);
	system("pause");
	return 0;
}
/*输出结果:
点在圆内
请按任意键继续. . .*/

(九)构造函数和析构函数

1.定义以及特点

构造函数:初始化赋值操作

析构函数:清理

构造方法:是在给实例对象  给对象属性赋初始值

特殊性:

1.在方法名前不需要写返回值类型

2.方法名=类名

3.实例化对象自动调用

4.默认构造方法:没有形参的构造方法 如果一个类中没有自定义构造 在编译时系统会自动给这个类添加一个默认的构造方法

5.构造方法的代码:给属性复制的代码

在c++中任何一个类都有构造方法(正确)

#include<iostream>
using namespace std;
class person
{
public:
	person()
	{
		cout << "构造函数的调用" << endl;//你写了构造函数,系统就会调用你自己写的构造函数,但是当你不写构造函数时,系统也会调用默认的构造函数,只不过这个构造函数是空实现
	}
	~person()
	{
		cout << "析构函数的调用" << endl;
	}
};
void test01()
{
	person p;//如果在test01中创建对象,那么它调用完test01之后就被释放了。而系统在释放test01之前会自动调用析构函数
}
int main()
{
	//而如果在main函数中创建对象,那么代码运行到system("pause");就停止了,不会那么快释放,所以暂时没有调用析构函数;等到整段代码执行完之后,他才会调用析构函数
	//person p;  
	test01();
	system("pause");
	return 0;
}

/*输出结果:
构造函数的调用
析构函数的调用
请按任意键继续. . .*/

2.构造函数的分类与调用

#include<iostream>
using namespace std;
//参数构造:有参构造(默认构造)、无参构造
//函数:拷贝、构造
class Person
{
public:
 Person()
	{
	 cout << "person的无参构造方法的调用" << endl;
    }
 Person(int a)
 {
	 age = a;
	 cout << "person的有参构造方法的调用" << endl;
 }
 Person(const Person& p)
 {
	 age = p.age;
	 cout << "person的拷贝函数的调用" << endl;
 }
 int age;
 ~Person()
 {
	 cout << "person的析构方法的调用" << endl;
 }
};
void test01()
{
	//三种调用方法: 1、括号法(默认调用法)
	Person p1;//(默认调用法)
	//注意:写默认调用法的时候不要带();当写成Person p1();的时候会被认为是函数的声明,不会认为在创建对象
    Person p2(10);
	Person p3(p1);
	//2、显示法
	//Person p4 =Person (10);//有参函数
	//Person p5 = Person(p1);//拷贝函数
	//Person(10);//此行代码属于匿名对象(特点:当前行执行后,系统会自动回收匿名对象)
	// 注意事项2:不要用拷贝函数初始化匿名对象  Person(p3);====Person p3;  ;
	//3、隐式转换法
   // Person p6 = 10; // 有参构造;相当于写了Person p4 =Person (10);
   // Person p7 = p4; //拷贝构造
}

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

/*输出结果:
person的无参构造方法的调用
person的有参构造方法的调用
person的拷贝函数的调用
person的析构方法的调用
person的析构方法的调用
person的析构方法的调用
请按任意键继续. . .*/

3.拷贝构造函数的调用时机

#include<iostream>
using namespace std;
//拷贝构造的三种调用时机
class person
{
public:
	person()
	{
		cout << "person默认函数调用" << endl;
	}
	person(int age)
	{
		m_age = age;
		cout << "年龄为:" << m_age << endl;
		cout << "person有参函数调用" << endl;
	}
	person(const person& p)
	{
		m_age = p.m_age;
		cout << "person拷贝函数调用" << endl;
	}
	~person()
	{
		cout << "person析构函数调用" << endl;
	}

	int m_age;
};

//1.使用一个已经创建完毕的对象来初始化一个新对象
 void test01()
{
	 person p1(10);
	 person p2(p1);
	 cout << "p2的年龄为:" << p2.m_age << endl;
}
//2.值传递的方式给函数参数传值
 void dowork(person p)
 {
 }
 void test02()
 {
	 person p;//调用默认构造函数
	//值传递相当于Person p = p 拷贝构造函数隐式写法;当实参给形参传值时,将实参的数据拷贝一份给形参
	 dowork(p);
}
//3.值方式返回局部对象
person dowork2()
 {
	person p1;//函数对象有个特点,函数执行完之后就要被释放掉
	return p1;//返回的并不是p1本身,而是仿照p1创建了一个新的对象,然后返回给test03
 }
 void test03()
 {
	 person p = dowork2();
 }
int main()
{
	//test01();
	/*test02();*/
	test03();
	system("pause");
	return 0;
}
/*输出结果:
person默认函数调用
person拷贝函数调用
person析构函数调用
person析构函数调用
请按任意键继续. . .*/

4.构造函数的调用规则

#include<iostream>
using namespace std;
/*构造函数调用规则
1.只要创建一个类,系统至少给一个类添加三个函数:默认构造函数 默认析构函数 默认拷贝函数
2.如果你写了有参构造函数,c++不再提供默认构造函数,会提供拷贝构造函数
3.如果你写了拷贝构造函数,c++不再提供其他构造函数*/
class person
{
public:
	person()
	{
		cout << "person默认函数调用" << endl;
	}
	person(int age)
	{
		m_age = age;
		cout << "年龄为:" << m_age << endl;
		cout << "person有参函数调用" << endl;
	}
	person(const person& p)
	{
		m_age = p.m_age;
		cout << "person拷贝函数调用" << endl;
	}
	~person()
	{
		cout << "person析构函数调用" << endl;
	}

	int m_age;
};
void test01()
{
	person p;
	p.m_age = 18;
	person p2(p);
	cout << "p2的年龄为:" << p2.m_age << endl;
}
int main()
{
	test01();
	system("pause");
	return 0;
}
/*输出结果:
person默认函数调用
person拷贝函数调用
p2的年龄为:18
person析构函数调用
person析构函数调用
请按任意键继续. . .*/

5.深拷贝与浅拷贝

浅拷贝:简单的值拷贝

深拷贝:在内存中重新申请一块空间,进行拷贝操作

#include<iostream>
using namespace std;
class person
{
public:
	person()
	{
		cout << "person默认函数调用" << endl;
	}
	person(int age,int height)
	{
		m_age = age;
		m_height = new int(height);
		cout << "年龄为:" << m_age << endl;
		cout << "person有参函数调用" << endl;
	}
	person(const person& p)
	{
		m_age = p.m_age;
		m_height = new int(*p.m_height);
		cout << "person拷贝函数调用" << endl;
	}
	//浅拷贝所带来的问题用深拷贝来解决
	~person()//将堆区开辟的数据进行释放操作
	{
		if (m_height != NULL)
		{
			delete m_height;
			m_height = NULL;
		}
		cout << "person析构函数调用" << endl;
	}

	int m_age;
	int* m_height;
};
void test01()
{
	person p1(18,160);
	cout << "p1的年龄为:"<<p1.m_age << "p1的身高为:"<<*p1.m_height << endl;
	person p2(p1);
	cout << "p2的年龄为:" << p2.m_age << "p2的身高为:" << *p2.m_height << endl;
}
int main()
{
	test01();
	system("pause");
	return 0;
}
/*输出结果:
年龄为:18
person有参函数调用
p1的年龄为:18p1的身高为:160
person拷贝函数调用
p2的年龄为:18p2的身高为:160
person析构函数调用
person析构函数调用
请按任意键继续. . .*/

(十)初始化列表

#include<iostream>
using namespace std;
class person
{
public:
	//person(int age,string name,int height)
	//{
	//	m_age = age;
	//	m_name = name;
	//	m_height = height;
	//}
	person(int age, string name, int height) :m_age(age), m_name(name), m_height(height)
	{

	}
	~person()
	{
		cout << "调用析构函数" << endl;
     }
	int m_age;
	string m_name;
	int m_height;
};
//void test01()
//{
//	person p(18, "熊二", 178);
//	cout << "年龄:" << p.m_age << "姓名" << p.m_name << "身高" << p.m_height << endl;
//}
void test02()
{
	person p1(10, "熊二", 180);
	cout << "年龄:" << p1.m_age << "姓名" << p1.m_name << "身高" << p1.m_height << endl;
}
int main()
{
	/*test01();*/
	test02();
	system("pause");
	return 0;
}
/*输出结果:
年龄:10姓名熊二身高180
调用析构函数
请按任意键继续. . .
*/

(十一)类对象作为类成员

#include<iostream>
#include<string>
using namespace std;
//2.定义一个手机类
class phone
{
public:
	phone(string pname) //给手机类m_pname属性赋值传值,即初始化
	{
		cout << "调用phone的有参构造函数" << endl;
		m_pname = pname;
	}
	~phone()
	{
		cout << "调用phone的析构函数" << endl;
	}
	string m_pname;
};
//1.定义一个人类
class person
{
public:
	//phone m_phone = pName;隐式转换法    :利用一个字符串给对象进行初始化的操作
	person(string name, string pName) :m_name(name), m_phone(pName)
	{
		m_name = name;
		m_phone = pName;
	}
	~person()
	{
		cout << "调用person的析构函数" << endl;
	}
	//两个属性
	string m_name;//名字
	phone m_phone;//电话号码
};

void test01()
{
	person p("张三","苹果MAX");//test01中实例化一个对象p
	cout  << p.m_name<< "拿着:"<< p.m_phone.m_pname << endl;
	
}

int main()
{
	test01();//调用test01函数
	system("pause");
	return 0;
}
/*
调用phone的有参构造函数
调用phone的有参构造函数
调用phone的析构函数
张三拿着:苹果MAX
调用person的析构函数
调用phone的析构函数
请按任意键继续. . .
*/

(十二)静态成员

静态成员变量

1.所有对象共享同一份数据

2.在编译阶段分配内存(没有运行前就分配了内存)

3.类内声明,类外初始化;(必须有一个初始值)

#include<iostream>
using namespace std;
/*静态成员变量:
1.所有对象共享同一份数据
2.在编译阶段分配内存(没有运行前就分配了内存)
3.类内声明,类外初始化;(必须有一个初始值)
4.静态成员变量也有访问权限*/

class person
{
public:
	//所有对象共享同一份数据
	static int m_A; //类内声明 类外定义 一步都不能少
private:
	static int m_B;
};

int person::m_A = 100; //类外定义
//int person::m_B = 200;//类外访问不到私有成员静态变量
void test01()
{
	//person p;//实例化一个对象
	//cout << p.m_A << endl;
	//person p2;
	//p2.m_A = 200;
	//cout << p.m_A << endl;
	//m_A是静态变量,所以调用的静态变量是一个唯一的值,此时p和p2是同一个内存空间,所以通过对象p访问静态变量,把值改了之后,p2的值也会改变
}

void test02()
{
	//	静态成员变量不属于某个对象,所有对象共享同一份数据
    //因此静态成员变量有两种访问方式:
    // 1.通过对象访问
	//person p;//实例化一个对象
	//cout << p.m_A << endl;
	// 2.通过类进行访问
	cout << person::m_A << endl;
}

int main()
{
	/*test01();*/
	test02();
	system("pause");
	return 0;
}
/*test01输出结果:
100
200
请按任意键继续. . .
test02输出结果:
100
请按任意键继续. . .
*/

静态成员函数

1.所有对象共享静态成员函数

2.静态成员函数只能调用静态成员变量

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值