目录
(六)封装属性private protected public
(一)内存分区模型
程序运行前:
(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.静态成员函数只能调用静态成员变量