目录
一、构造函数和析构函数(对象的初始化和清理)
作用
功能实现
二、构造函数
语法:类名 () {}
三、析构函数
语法 ~类名(){}
四、构造函数的分类及调用
五、拷贝构造函数的调用时机
六、构造函数调用规则
七、深拷贝与浅拷贝的问题
八、初始化列表
九、类对象作为类成员
十、静态成员
1.静态成员分类
2.静态成员变量
3.静态成员函数
对象的初始化和清理
生活中我们买的电子产品都基本会有出厂设罩,在某一天我们不用时候也会删除一些自己信息数据保证安全
C++中的面向对象来源于生活,每个对象也都会有初始设置以及对象销毁前的清理数据的设置。
一个对象或者变量没有初始状态,对其使用后果是未知的,
同样的使用完一个对象或变量没有及时清理,也会造成一定的安全问题
C++利用构造函数和析构函数解决上述问题,这两个函数将会被编译器自动调用,完成对象初始化和清理工作对象的初始化和清理工作是编译器强制我们要做的事情,因此如果我们不提供构造和析构,编译器会提供编译器提供的构造函数和析构函数是空实现。
示例:
#include
using namespace std;
class person{
public:// 在公共作用域下在主函数才能访问到
// 构造函数
person()
{
// 在创建一个对象的时候会自动调用一次
cout<<"person 构造函数的调用"<
运行结果:
示例:
#include
using namespace std;
class person{
public:// 在公共作用域下在主函数才能访问到
// 析构函数
~person ()
{
cout<<"析构函数的调用"<
运行结果:
两种分类方式:
三种调用方式:
示例:
#include
using namespace std;
class person {
public:
// 构造函数
person() // 无参
{
cout << "person 的无参数的构造函数调用。" << endl;
}
person(int a) // 有参
{
age = a;
cout << "person 的有参数的构造函数调用。" << endl;
}
// 拷贝构造函数
person(const person& p)
{
// 把另一个person的属性传入进来 +const 防止改变原来的属性
// 将传入的人身上的所有的属性全部拷贝到自己的身上
age = p.age;
cout << "person 的拷贝构造函数调用。" << endl;
}
// 析构函数
~person()
{
cout << "person 的析构函数的调用。" << endl;
}
int age;
};
void test()
{
// 调用
// 1. 括号法
cout << "括号法调用" << endl;
person p1; // 默认构造函数调用
// 注意事项1:默认构造函数的调用不要加() 因为会被认为是一个函数的声明,不会认为在创建对象
person p2(10); // 调用有参构造函数
// 拷贝构造函数的调用
person p3(p2); // 拷贝构造函数的调用
cout << "p2的年龄:" << p2.age << endl;
cout << "p3的年龄:" << p3.age << endl;
cout << endl;
// 2. 显示法
cout << "显示法调用" << endl;
person p4; // 默认构造函数
person p5 = person(10); // 有参构造
person p6 = person(p3); // 拷贝构造
// 右侧相当于匿名对象,当执行结束后系统会立即回收掉匿名对象
// 注意事项2:不要利用拷贝构造函数 初始化 匿名对象
// 编译器会认为 person(p3) === person p3,相当于时对象的声明
cout << endl;
cout << "测试匿名对象" << endl;
person(10);
cout << "aaa" << endl << endl;
// 3. 隐式转换法
cout << "隐式转换法调用" << endl;
person p7 = 10; // 相当于person p3 = person(10);是一种有参构造
person p8 = p7;
cout << endl;
}
int main()
{
test();
return 0;
system("pause");
}
运行结果:
C++中拷贝构造函数调用的时机通常有三种情况:
示例:
#include
using namespace std;
// 拷贝函数的三种调用时机
class person {
public:
person()
{
cout << "person 的默认函数构造" << endl;
}
// 有参
person(int in_age)
{
age = in_age;
cout << "有参构造函数" << endl;
}
// 拷贝
person(const person& p)
{
age = p.age;
cout << "拷贝构造函数" << endl;
}
// 析构
~person()
{
cout << "person 的析构函数的调用" << endl;
}
//private:
int age;
};
// 1. 使用一个已经创建完毕的对象来初始化一个新的对象
void test01()
{
person p1(20); // 有参构造
person p2(p1); // 拷贝构造
cout << "p2的年龄为:" << p2.age << endl;
}
// 2.值传递的方式给函数参数传值
void do_work(person p)
{
}
void test02()
{
person p;
do_work(p);
}
// 3. 以值的方式返回局部对象
person do_work2()
{
person p1;
cout << (int*)&p1 << endl;
return p1; // 拷贝一个新的对象用于返回
}
void test03()
{
person p = do_work2(); // 得到的是拷贝的返回值
cout << (int*)&p << endl;
}
int main()
{
test01();
cout << endl;
test02();
cout << endl;
test03();
return 0;
}
运行结果:
示例:
#include
using namespace std;
class person
{
public:
// 默认
person()
{
cout<<"person 的默认函数构造"<age = p.age;
cout<<"person 的拷贝构造函数"<
运行结果:
浅拷贝带来的问题是堆区的内存重复释放,利用深拷贝来解决。
示例:
#include
using namespace std;
class person
{
public:
// 默认
person()
{
cout<<"person 的默认函数构造"<age = age;
cout<<"person 的有参构造函数"<height = new double(height); // new 一个新的指针变量,创建在堆区
}
// 拷贝
person(const person & p)
{
this->age = p.age; // 编译器默认实现
cout<<"person 的拷贝构造函数"<age = p.height; // 编译器的 拷贝构造默认实现方式
// 解决浅拷贝带来的问题
// 两个对象的指针分别设立在不同的存储地址
this->height = new double(*p.height); // 利用深拷贝来解决浅拷贝的问题
}
// 析构
~person()
{
// 将我们在堆区开辟的数据做释放操作
if(height !=NULL){
delete height;
height = NULL;
}
cout<<"person 的析构函数的调用"<
运行结果:
作用:C++提供了初始化列表语法,用来初始化属性。
语法 : 构造函数():属性1(值1),属性2(值2)... {}
示例:
#include
using namespace std;
class person
{
public:
// 传统初始化操作
/*person(int a ,int b,int c)
{
A = a;
B = b;
C = c;
}*/
// 初始化列表属性,赋值默认值
/*person():A(10),B(20),C(30)
{
}*/
// 设置成变量
person(int a,int b,int c):A(a),B(b),C(c)
{
}
int A;
int B;
int C;
};
void test01()
{
// 每次调用一种
person p(10,20,30);
cout<<"A = "<
运行结果:
c++类中的成员是另一个类的对象,称该成员为对象成员
例如:
class A{};
class B
{
A a;
};
B类中有对象A作为成员,A为对象成员
那么,当创建B对象时,A与B的构造和析构顺序ABBA
示例:
#include
#include
using namespace std;
// 设计一个手机类
class phone{
public:
// 给手机命名
// 构造函数
phone(string in_name)
{
p_name = in_name;
cout<<"这是phone的构造函数调用"<
运行结果:
静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员
静态成员变量:
静态成员函数:
示例:
#include
#include
using namespace std;
class person {
public:
static int m_A; // 静态成员变量
// 类内声明,类外初始化
private:
static int m_B;// 静态成员变量
// 在类外访问不到
};
int person::m_A = 0;
int person::m_B = 200;
// 两种访问方式
void test01()
{
// 1. 通过对象访问
cout << "通过对象访问" << endl;
person p1;
cout << "p1_a = " << p1.m_A << endl;
person p2;
p2.m_A = 200;
cout << "共享数据,p2修改了数据,p1访问就变为p2修改后内容" << endl;
cout << "p1_a = " << p1.m_A << endl;
cout << "p2_a = " << p2.m_A << endl;
// 2. 通过类名访问
cout << "通过类名访问:" << person::m_A << endl;
//并且私有权限类外访问不到
}
int main()
{
test01();
return 0;
}
运行结果:
示例:
#include
#include
using namespace std;
class person{
public:
// 静态的成员函数
static void func()
{
m_A = 100;
// m_B = 200; // 静态成员函数不能访问非静态成员变量
// 静态成员函数是每个对象都共享的,调用非静态成员变量时不知道修改的是哪个对象的变量
cout<<"静态函数的调用"<
运行结果: