1、构造函数和析构函数
#include<iostream>
using namespace std;
//1、构造函数 进行初始化操作
class person
{
//1、构造函数
//没有返回值,不用写void
/*函数名和类名相同
构造函数可以有参数,可以发生函数重载
创建对象时,构造函数会自动调用,而且只会调用一次*/
public:
person()
{
cout << "函数的调用" << endl;
}
//2、析构函数
//没有返回值,不用写void
//函数名和类名相同 在名称前加 ~
//构造函数不可以有参数,不可以发生函数重载
//对象在销毁前,会自动调用析构函数,而且只会调用一次
~person()
{
cout << "析构函数函数的调用" << endl;
}
};
//构造函数和析构函数都是必须有的实现,如果我们自己不提供,编译器会提供一个空实现的构造和析构
void test01()
{
person p;//栈区 上的数据,test01执行完毕后,释放这个对象
}
int main()
{
test01();
system("pause");
return 0;
}
2、构造函数的分类与调用
#include<iostream>
using namespace std;
//1、分类
// 按照有无参数分类 无参构造(默认构造)和 有参构造
// 按照类型分类 普通构造 拷贝构造
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 test02()
{
//1.括号法
//person p1;//默认构造函数
//person p2(10);//有参构造函数
//person p3(p1);//拷贝构造函数
//注意事项
//调用默认构造函数时不要加()
//因为下面这行代码,编译器会认为是一个函数的声明,不会认为在创建对象
//person p();
//2.显示法
person p1;
person p2 = person(10);//有参构造
person p3 = person(p2);//拷贝构造
//注意事项2.1:person(10);//匿名函数 特点:当前行执行结束后,系统会立即回收匿名对象
//cout << "aaa" << endl;
//2.2不要利用拷贝构造函数 初始化匿名对象 编译器会认为 person(p3) == person p3;即对象的声明
//person(p3);
/*cout << "p2的年龄:" << p2.age << endl;
cout << "p3的年龄:" << p3.age << endl;*/
//3.隐式转换法
person p4 = 10;//相当于写了 person p4 = person(10);即有参构造函数
person p5 = p4;
}
int main()
{
test02();
return 0;
}
3、拷贝构造函数的调用时机
#include<iostream>
using namespace std;
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;
};
//1.使用一个已经创建完毕的对象来初始化一个新对象
void test03()
{
person p1(10);
person p2(p1);
}
//2.值传递的方式给函数参数传值
void dowork(person pp)//值传递 相当于隐式转换法 person pp = p3;
{
}
void test04()
{
person p3;
dowork(p3);//相当于隐式转换法 person pp = p3;
}
//3.值方式返回局部对象
person dowork2()
{
person p6;
cout << &p6 << endl;
return p6;//局部变量在函数执行完后会自动释放,因此需要要一个变量来接受p6,即从test05;
}
void test05()
{
person p = dowork2();//隐式转换法
cout << &p << endl;
}
int main()
{
test05();
return 0;
}
4、构造函数的调用规则
#include<iostream>
using namespace std;
//构造函数的调用规则
//1、创建一个类,c++编译器会给每个类都添加至少3个函数
//默认构造函数(空实现)
//析构函数(空实现)
//拷贝构造(值拷贝) //注释原有的拷贝函数实现后即23行到27行,值依然可以复制到拷贝函数
//2、如果我们写了有参构造函数,编译器就不再提供默认构造,依然提供拷贝构造
//3、如果我们写了拷贝构造函数,编译器就不再提供其他构造函数
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 test001()
//{
// person p1;
// p1.age = 18;
// person p2(p1);
//
// cout << p2.age << endl;
//}
//void test002()
//{
// person p1(28);
// person p2(p1);
// cout << p2.age << endl;
//}
void test003()
{
person p1 = person(p1);
}
int main()
{
//test001();
//test002();
test003();
return 0;
}
5、浅拷贝和深拷贝
浅拷贝的问题其实就是两个对象的指针重复释放同一块内存导致非法操作
要解决问题要使用深拷贝操作,即new出来一块内存来顶替原来的那个指针
#include<iostream>
using namespace std;
class person
{
public:
person()
{
cout << "无参构造函数的调用" << endl;
}
person(int a,int hight)
{
age = a;
m_hight = new int(hight);
cout << "有参构造函数的调用" << endl;
}
person(const person& p)
{
cout << "拷贝构造函数的调用" << endl;
age = p.age;
//m_hight = p.m_hight;//浅拷贝的就是编译器默认实现这行代码
//深拷贝操作,防止两个对象的指针对应的数据二次释放造成的非法操作
m_hight = new int(*p.m_hight);
}
~person()
{
//析构代码,将堆区开辟数据作释放的操作
if (m_hight != NULL)
{
delete m_hight;
m_hight = NULL;
}
cout << "析构构造函数的调用" << endl;
}
int age;
int* m_hight;
};
void test01()
{
person p1(18, 160);
cout << p1.age << *p1.m_hight << endl;
person p2(p1);
cout << p2.age << *p2.m_hight << endl;
}
int main()
{
test01();
return 0;
}
6、初始化列表初始化值
#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(30,20,10);
cout << p.m_a << endl;
cout << p.m_b << endl;
cout << p.m_c << endl;
}
int main()
{
test01();
return 0;
}
7、类对象作为类成员
#include<iostream>
using namespace std;
class phone
{
public:
phone(string pname)
{
cout << "phone" << endl;
m_pname = pname;
}
~phone()
{
cout << "phone析构构造函数的调用" << endl;
}
string m_pname;
};
class person
{
public:
person(string name, string pname) :m_name(name), m_phone(pname)
{
cout << "person" << endl;
}
~person()
{
cout << "person析构构造函数的调用" << endl;
}
string m_pname;
string m_name;
phone m_phone;
};
//当其他类对象作为本类成员,构造时候先构造其他类对象,再构造本身;析构的顺序与构造相反
void test()
{
person p("张三", "华为");
cout << p.m_name << "拿着" << p.m_phone.m_pname << endl;
}
int main()
{
test();
return 0;
}
8、静态成员变量
#include<iostream>
using namespace std;
class person
{
//静态成员变量
public:
//1、所有对象都共享一份数据
//2、在编译阶段分配内存
//3、类内声明,类外初始化操作
static int m_a;
//静态成员变量也是有访问权限的
private:
static int m_b;
};
int person::m_a = 100;//3.2类外初始化操作
int person::m_b = 200;
void test()
{
person p;
cout << p.m_a << endl;
person p2;
p2.m_a = 200;
cout << p.m_a << endl; //1、所有对象都共享一份数据;所以用p去访问时为200
}
void test02()
{
//静态成员变量 不属于某个对象上,所有对象都共享同一份数据
//因此静态成员变量有两种访问方式
//1、通过对象进行访问
//person p;
//cout << p.m_a << endl;
//2、通过类名进行访问
cout << person::m_a << endl;
//cout << person::m_b << endl;//静态成员变量也是有访问权限的
}
int main()
{
//test();
test02();
return 0;
}
9、静态成员函数
#include<iostream>
using namespace std;
class person
{
public:
//静态成员函数
//1.所有对象共享同一个函数
//2.静态成员函数只能访问静态成员变量
static void func()
{
cout << "static void func的调用" << endl;
m_a = 200; //静态成员函数可以访问静态成员变量
//m_b = 300;//静态成员函数不可以访问非静态成员变量,因为非静态成员变量是某个对象有的,所以无法区分到底是哪个对象的
}
//静态成员变量
static int m_a;//记得类内声明,类外初始化
int m_b;//非静态成员变量
//静态成员函数也是有访问权限的
private:
static void func02()
{
cout << "static void func02的调用" << endl;
}
};
int person::m_a = 100;
void test()
{
//两种访问方式
//1、通过对象访问
person p;
p.func();
//2、通过类名访问 //所有对象共享同一个函数
person::func();
//person::func02(); 静态成员函数也是有访问权限的
}
int main()
{
test();
return 0;
}