作用:对象的初始化和清理
1.构造函数
进行初始化操作,没有返回值,不用写void,
函数名与类名相同
构造函数可以有参数,可以发生重载啊
创建对象的时候,构造函数会自动调用 , 而且只会调用一次
2.析构函数
进行清理操作
没有返回值 不写void
函数名和类名相同 在名称前面加~
析构函数不可以有参数 不可以发生重载
对象在销毁钱会自动调用析构函数 而且只会调用一次
class person
{
public:
person()
{
cout <<"person构造函数的调用" << endl;
}
//2.析构函数
~person()
{
cout << "person的析构函数调用" << endl;
}
};
//构造和析构都是必须有的实现,如果我们自己不 提供,编译器会提供 一个空实现的构造和析构
3.构造函数的分类及其调用
构造函数的分类
按照参数分类:有参构造和无参构造(默认构造)。
按照类型分类:普通构造和拷贝构造函数
class person
{
public:
person()
{
cout << "无参构造函数的调用" << endl;
}
person(int a)
{
age = a;
cout << "有参构造函数的调用" << endl;
}
//拷贝构造函数
person(const person &p)//不能改变原来的数据
{
//将传入的人身上所有的属性,拷贝到我身上
age = p.age;
}
~person()
{
cout << "析构函数的调用" << endl;
}
int age;
};
构造函数的调用
1.括号法
person p1; //调用默认构造函数
person p2(10);//有参构造函数调用
person p3(p2);//拷贝构造函数
注意:1.调用默认构造函数的时候,不要加(),因为编译器会认为下面这行代码是一个函数的声明,不是创建对象
person p1();
void func();
2.显示法
person p5 = person(10); //有参构造
person p6 = person(p5);//拷贝构造person(10);//匿名对象,等号左边是名字 当前执行结束后,系统会自动回收掉匿名对象
注意:2.不要 利用拷贝构造函数初始化匿名对象,编译器会认为是一个对象的声明
//person p6 = p6;
person (p6); //错误的
3.隐式转换法
person p7 = 10;
//相当于写了person p7 = person(10)
person p8 = p7;//拷贝构造
4.拷贝构造函数调用时机
1.使用一个已经创建完毕的对象来初始化一个新对象
void text01()
{
person p1(10);
person p2(p1);
}
2.值传递的方式给函数参数传值
void dowork(person p)
{
}void text02()
{
person p;
dowork(p);
}
3.以值方式返回局部对象
person dowork2()
{
person p1;
cout << (int*)&p1 << endl; //局部变量,执行完之后被释放。
return p1;
}void text03()
{
person p = dowork2();
cout << (int*)&p << endl;
}
5.构造函数的调用规则
默认情况下,C++编译器至少给一个类添加三个函数
1.默认构造函数(无参,函数体为空)
2.默认析构函数(无参,函数体为空)
3.默认拷贝构造函数(对属性进行值拷贝)
构造函数调用规则
1.如果我们写了有参构造函数,那么编译器就不再提供默认构造函数,仍然提供拷贝构造函数
2.如果我们写了拷贝构造函数,那么编译器就不再提供普通构造函数(默认构造函数)
6.深拷贝与浅拷贝
浅拷贝:简单的赋值拷贝(等号赋值操作,利用编译器提供的拷贝析构函数)
深拷贝:在堆区重新申请空间,进行拷贝操作
注意:如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题(重复释放堆空间(非法操作))
#include<iostream>
using namespace std;
class person
{
public:
person()
{
cout << "默认构造函数的调用" << endl;
}
person(int age,int height)
{
m_age = age;
m_height = new int(height);//堆区
cout << "有参构造函数调用" << endl;
}
person(const person &p)
{
cout << "person 拷贝构造函数调用" << endl;
//浅拷贝
//m_height = p.m_height ;
//深拷贝操作
m_age = p.m_age ;
m_height = new int(*p.m_height );
}
~person()
{//析构代码,将堆区开辟数据做释放操作
if(m_height != NULL)
{
delete m_height;
m_height = NULL;
}
cout << "析构函数调用" << endl;
}
int m_age;
int *m_height;
};
void test01()
{
person p1(18,160);//在栈区,后进先出,所以p2先被释放
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();
return 0;
}
若使用编译器提供的拷贝构造函数,则可能会造成堆空间的重复释放
7.初始化列表
c++提供的初始化列表语法,用来初始化属性
语法:构造函数():属性1(值1),属性2(值2)......{ }
#include<iostream>
using namespace std;
//初始化列表
class person
{
public:
//传统初始化操作
// person(int a,int b,int c)
// {
// m_a = a;
// m_b = b;
// m_c = c;
// }
//初始化列表初始化属性
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 test01()
{
person p(10,20,30);
cout << "m_a = " << p.m_a << endl;
cout << "m_b = " << p.m_b << endl;
cout << "m_c = " << p.m_c << endl;
}
int main()
{
test01();
}
8.类对象作为类成员
c++类中的成员可以是了另一个类的对象,我们称该成员为对象成员
当类对象做为本类成员,构造时候先构造其他类对象,再构造自身
析构的顺序?
先释放自身,再释放其他类对象
#include<iostream>
#include<string>
using namespace std;
class phone
{
public:
phone(string pname)
{
m_pname = pname;
}
//爪机品牌名称
string m_pname;
};
class person
{
public:
//姓名
person(string name,string pname):m_name(name),m_phone(pname)
{
}
string m_name;
//手机
phone m_phone;
};
void test01()
{
person p("张三","苹果max");
cout << "姓名" << p.m_name << endl;
cout << "爪机" << p.m_phone.m_pname << endl;
}
int main()
{
test01();
return 0;
}
9.静态成员
在成员变量和成员函数前面加上关键字static ,称为静态成员
静态成员分类
1.静态成员变量
注意事项:
1.所有对象共享同一份数据,一个改了其他人看到的数据也改了
2.在编译阶段分配内存,生成.exe程序还没有运行之前,就已经分配好内存了
3.类内声明,类外初始化
4.静态成员变量也是有访问权限的
5.访问方式有两种
(1)通过对象进行访问
(2)通过域名进行访问
#include<iostream>
#include<string>
using namespace std;
class person{
public:
//所有对象都共享同一份数据
//编译阶段分配内存,
//类内声明,类外初始化
//访问权限
static int m_a;
private://出了这个类,类外是不可以访问的
static int m_b;
};
//int m_a = 100;//全局变量
int person::m_a = 100;//person 作用域下的m_a;
int person::m_b = 200;
void test01()
{
person p;
cout << p.m_a << endl;//100
person p2;
p2.m_a = 200;
cout << p.m_a << endl;//200
}
void test02()
{
//静态成员变量不属于某个对象,所有对象共享同一份数据
//因此静态成员变量有两种访问方式
//1. 通过对象进行访问
person p;
cout << p.m_a << endl;
//2.通过域名进行访问
cout << person ::m_a << endl;
//cout << person::m_b<< endl;
//private 不可以被访问
}
int main()
{
//test01();
test02();
}
2.静态成员函数
注意事项:
1.所有对象共享同一个函数
2.静态成员函数只能访问静态成员变量
3.静态成员含漱液的访问权限(类外访问不到私有的静态成员函数)
#include<iostream>
#include<string>
using namespace std;
//静态成员函数
//所有对象共享同一个函数
//静态成员函数只能访问静态成员变量
class person{
public:
//静态成员函数
static void func()
{
m_a = 200;//静态成员函数可以访问静态成员变量
m_b = 300;//报错,静态成员函数不能访问非静态成员变量
//m_b必须通过一个对象才能访问这块内存,如果有多个对象,无法区分到底是给哪个对象的m_b赋值
cout << "static void func调用" << endl;
}
static int m_a;//静态成员变量 (类内声明,类外初始化)
int m_b;
//静态成员函数的访问权限
private://类外访问不到私有 的静态成员函数
static void func2()
{
cout << "static void func2调用" << endl;
}
};
int person :: m_a = 100;
void test01()
{
//1.对象
person p;
p.func();
//2.类名
person::func ();
//cout << person :: m_a << endl;
}
int main()
{
test01();
}