C++学习---类和对象之对象的初始化和清理
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
C++学习---类和对象之对象的初始化和清理⼆、对象的初始化和清理
1、构造函数和析构函数
#include <iostream>
#include <string>
using namespace std;
//对象初始化和清理
//1.构造函数进⾏初始化操作
class Person {
public:
//1、构造函数:
/*
1.没有返回值不写void
2.函数名与类名相同
3.构造函数可以有参数,可以发⽣重载
4.创建对象的时候,构造函数会⾃动调⽤,⽽且之调⽤⼀次
*/
Person() {
cout << " Person构造函数的调⽤ " << endl;
}
//2、析构函数进⾏清理的操作
/*
1.没有返回值,不写void
2.函数名和类名相同在名称前加~
3.析构函数不可以有参数的,不可以发⽣重载
4.对象在销毁前会⾃动调⽤析构函数,⽽且只会调⽤⼀次
*/
~Person() {
cout << " Person 析构函数调⽤ " << endl;
}
};
//构造和析构都是必须有的实现
//如果⾃⼰不提供,编译器会提供⼀个空实现的构造和析构
void test01(){
Person p; //栈上的数据,test01执⾏完毕后,释放这个对象
}
int main() {
//test01();
Person p;
system("pause");
return0;
}
2、构造函数的分类及调⽤
#include <iostream>
#include <string>
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;
}
~Person() {
cout << " Person 的析构函数调⽤ " << endl;
}
int age;
};
//调⽤
void test01() {
//1.括号法,常⽤
Person p1; //默认构造函数调⽤
Person p2(10); //有参构造函数
Person p3(p2); //拷贝构造函数
cout << "p2 的年龄:" << p2.age << endl;
cout << "p3 的年龄:" << p3.age << endl;
//注意事项1
//调⽤默认构造函数的时候,不要加()
//当写了()之后就不会创建对象了
//下⾯这⾏代码,编译器会认为是函数声明,不会认为在创建对象 //Person pX(); //⽆参数,返回值是Person
//2.显⽰法
Person p4; //⽆参构造函数
Person p5 = Person(20); //有参构造函数
Person p6 = Person(p5); //拷贝构造函数
//匿名对象,特点:当前⾏执⾏结束后,系统会⽴即回收掉匿名对象 Person(10);
cout << "aaa" << endl;
//注意事项2
//不要利⽤拷贝构造函数,初始化匿名对象
//编译器会认为Person(p4) 等价于 Person p4,p4是对象的声明; //编译器报错为 Person p4 重定义
//Person(p4);
//3.隐式转换法
Person p7 = 15; //相当于 Person p7 = Person(15);
Person p8 = p7; //拷贝构造
}
int main() {
test01();
system("pause");
return0;
}
3、拷贝构造函数调⽤时机
#include <iostream>
#include <string>
using namespace std;
//拷贝构造函数的调⽤时机
//1.使⽤⼀个已经创建完毕的对象来初始化⼀个新对象
//2.值传递的⽅式给函数参数传值
//3.⽤值的⽅式返回局部的对象
class Person {
public:
Person() {
cout << "Person 的⽆参(默认)构造函数调⽤ " << endl;
}
Person(int age) {
m_Age = age;
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(20); //⽆参构造函数调⽤
Person p2(p1); //拷贝构造函数调⽤
cout << "p2的年龄:" << p2.m_Age << endl;
}
//2.值传递的⽅式给函数参数传值
void doWork(Person p) {
}
void test02() {
Person p; //⽆参构造函数调⽤
doWork(p); //拷贝构造函数调⽤
}
//3.⽤值的⽅式返回局部的对象
Person doWork2() {
Person p1;
cout << (int *)&p1 << endl;
return p1;
}
void test03() {
Person p = doWork2(); //拷贝构造函数调⽤
cout << (int *)&p << endl;
}
int main() {
//test01();
//test02();
test03();
system("pause");
return0;
}
4、构造函数的调⽤规则
#include <iostream>
#include <string>
using namespace std;
//构造函数的调⽤规则
//1.创建⼀个类,c++编译器会给每个类都添加⾄少3个函数
//默认构造(空实现)
//析构函数(空实现)
//拷贝构造(值拷贝)
//2.
//如果我们写了有参构造函数,编译器就不在提供默认构造(不能使⽤),依然提供拷贝构造(能使⽤)//如果我们写了拷贝构造函数,编译器就不再提供其他普通构造函数了
class Person {
public:
/*Person() {
cout << "Person 的⽆参(默认)构造函数调⽤" << endl;
}*/
Person(int age) {
m_Age = age;
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;
//}
void test02() {
Person p(20);
Person p2(p);
cout << "p2 的年龄:" << p2.m_Age << endl;
}
int main() {
//test01();
test02();
system("pause");
return0;
}
5、深拷贝与浅拷贝
编译器提供的拷贝构造函数是浅拷贝,对于有指针类型的成员,在调⽤浅拷贝构造函数和析构函数后有重复释放指针的问题,出现异常。
需要⾃⼰实现深拷贝构造函数重新开辟堆区空间解决此问题。
如果属性有在堆区开辟的,⼀定要⾃⼰提供拷贝构造函数,防⽌浅拷贝带来的问题
#include <iostream>
#include <string>
using namespace std;
class Person {
public:
Person() {
cout << "Person 的默认(⽆参)构造函数调⽤ " << endl;
}
Person(int age,int height) {
m_Age = age;
m_Height = new int(height);
cout << "Person 的有参构造函数调⽤ " << endl;
}
//⾃⼰实现拷贝构造函数解决浅拷贝带来的问题
Person(const Person &p) {
cout << "Person 的拷贝构造函数调⽤ " << endl;
m_Age = p.m_Age; //编译器默认实现的部分
//原来的浅拷贝
//m_Height = p.m_Height; //编译器默认实现的部分
//深拷贝
m_Height = new int(*p.m_Height);
}
//析构规则,先进后出。
先定义的变量最后调⽤析构
~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 << endl;
cout << "p1 的⾝⾼: " << *p1.m_Height << endl;
Person p2(p1); //编译器帮助做了浅拷贝,赋值操作
cout << "p2 的年龄: " << p2.m_Age << endl;
cout << "p2 的⾝⾼: " << *p2.m_Height << endl;
//浅拷贝带来的问题是,堆区的内存重复释放。
异常
//解决⽅式:利⽤深拷贝
}
int main() {
test01();
system("pause");
return0;
}
6、初始化列表
#include <iostream>
#include <string>
using namespace std;
class Person {
public:
//1.传统初始化操作,构造函数
/*Person(int a, int b, int c) {
m_A = a;
m_B = b;
m_C = c;
}*/
//2.利⽤初始化列表给参数赋初值
/*Person() :m_A(10), m_B(20), m_C(30) {
}*/
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);
//Person p;
Person p(30,20,10);
cout << "m_A = " << p.m_A << endl;
cout << "m_B = " << p.m_B << endl;
cout << "m_C = " << p.m_C << endl;
}
int main() {
test01();
system("pause");
return0;
}
7、类对象作为类成员
#include <iostream>
#include <string>
using namespace std;
//⼿机类
class Phone {
public:
Phone(string pName) {
m_PName = pName;
cout << " Phone 的构造函数调⽤ " << endl;
}
~Phone() {
cout << " Phone 的析构函数调⽤ " << endl;
}
//⼿机品牌名称
string m_PName;
};
//类对象作为类成员
class Person {
public:
//Phone m_Phone = pName; 隐式转换法
Person(string name, string pName) :m_Name(name), m_Phone(pName) { cout << " Person 的构造函数调⽤ " << endl;
}
~Person(){
cout << " Person 的析构函数调⽤ " << endl;
//姓名
string m_Name;
//⼿机
Phone m_Phone;
};
//当其他类的对象作为本类成员,构造时候先构造类对象,再构造⾃⾝//析构顺序与构造相反
void test01() {
Person p("张三","苹果MAX");
cout << p.m_Name << "拿着: " << p.m_Phone.m_PName << endl; }
int main() {
test01();
system("pause");
return0;
}
8、静态成员
#include <iostream>
#include <string>
using namespace std;
//静态成员函数
//1.所有对象共享同⼀个函数
//2.静态成员函数只能访问静态成员变量
class Person {
public:
//静态成员函数
static void func() {
m_A = 100; //静态成员函数可以访问静态成员变量
//静态成员函数不可以访问⾮静态成员变量
//m_B = 200; //⽆法区分到底是那个对象的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 = 0; //(类内声明,类外初始化)
//有两种访问⽅式访问静态成员函数
void test01() {
//1.通过对象访问
Person p;
p.func();
//2.通过类名访问
Person::func();
//Person::func2();// 类外访问不到私有静态成员函数
}
int main() {
test01();
system("pause");
return0;
}。