类和对象——对象的初始化和清理

.1构造函数和析构函数

若人为不实现,编译器会自动实现但函数内为空

构造函数:创建对象时为对象的成员属性赋值 类名(){}

  1. 没有返回值
  2. 可以有参数,可以重载
  3. 系统自动调用,不用手动调用,并且只调用一次

析构函数:对象销毁前清理工作 ~类名(){}

  1. 没有返回值
  2. 不可以有参数,无法重载
  3. 系统自动调用,不用手动调用,并且只调用一次

.2构造函数的分类及调用

按参数分类 无参构造(默认构造)和有参构造
按类型分类 普通构造和拷贝构造函数

class test {
	public:
		//无参构造 
		test() {
			cout <<"test的无参构造函数调用"<<endl;
		}
		//有参构造 
		test(int a) {
			cout <<"test的有参构造函数调用"<<endl;
		}
		//拷贝构造
		test(const test &p){
			//将p的成员属性拷贝到当前对象上 
			cout <<"test的拷贝构造函数调用"<<endl;
		} 
		
};

调用:

  1. 括号法
test p1;	//**
test p2(10);
test p3(p2);

注意:调用默认构造函数时不要加()。因为编译器会认为这是一个函数声明

  1. 显示法
test p1;
test p2=test(10);
test p3=test(p2); 

单独出现的test(10);称为匿名对象 特点:当前行执行结束,系统会立即回收匿名对象
注意:不要利用拷贝构造函数 初始化匿名对象。因为编译器会认为重定义对象声明test(p3);×

  1. 隐式转换法
test p2=10;		//有参构造
test p3=p2;		//拷贝构造

.3拷贝构造函数的调用时机

  1. 使用一个已经创建完的对象来初始化另一个
Person p1;
Person p2(p1);
  1. 值传递的方式给函数参数传值
void dotest(Person p) {
	//在该函数内调用拷贝构造函数,相当于一个副本 
	//不会更改函数外p的 成员属性 
}

void  test() {
	Person p;
	dotest(p);
}
  1. 值方式返回局部对象
Person dotest2() {
	Person p1;
	return p1;		//返回时根据p1创建一个新的对象 
}

.4构造函数调用规则

默认情况,编译器提供

  1. 默认构造函数(无参,函数体空)
  2. 默认析构函数(无参,函数体空)
  3. 默认拷贝构造函数,仅对属性进行值拷贝
  4. 赋值运算符operator= 对属性进行拷贝 (见.5赋值运算符重载

若自己定义有参构造函数,编译器不再提供①默认构造,但提供拷贝构造
若自己定义拷贝构造,编译器不再提供其他构造函数

.5深拷贝与浅拷贝

浅拷贝:简单的赋值,编译器自动实现的拷贝构造函数
深拷贝:堆区重新申请一片空间,进行拷贝构造操作

浅拷贝会造成堆区内存重复释放,因为仅仅赋值

#include <iostream> 
using  namespace std;

class Per {
public:
	Per() {
		cout << "Pe的默认构造函数调用" << endl;
	}

	Per(int age, int height) {
		m_age = age;
		m_height = new int(height);
		cout << "Pe的有参构造函数调用" << endl;
	}

	Per(const Per& p) {
		cout << "Pe的拷贝构造函数调用" << endl;
		m_age = p.m_age;
		//m_height=p.m_height;			编译器默认实现这行代码 浅拷贝
		m_height = new int(*p.m_height);		//深拷贝 在堆区开辟另一片区域
	}

	~Per() {
		//堆区有内存时,需要在析构函数中把内存释放
		if (m_height != NULL) {
			delete m_height;			//释放掉指针开辟的空间 
		}
		cout << "Pe的析构函数调用" << endl;
	}

	int  m_age;
	int* m_height;	 			//指针在堆区开辟新的空间 
};

void test1() {

	Per p1(12, 150);			//析构函数第一次释放掉 p1的指针m_height指向的内存空间 
	Per p2(p1);				//析构函数又一次释放p2的指针指向的内存空间,重复释放 
}

int main() {
	test1();

	system("pause");
	return 0;
}

.6初始化列表

语法:构造函数():属性1(值1),属性(值2){}

class Per {
public:
	Per(int a,int b,int c):m_a(a),m_b(b),m_c(c){}		//初始化列表

private:
	int m_a;
	int m_b;
	int m_c;
};

需要初始化时Per(10,20,30);即可

.7类对象作为成员属性

对象成员:类中成员是另一个类的对象
当其他类对象作为本类成员时,先构造类对象,在构造自身,析构顺序相反

class pen {
public:
	pen(string name) {
		m_pname = name;
		cout << "pen的构造函数调用" << endl;
	}
	string m_pname;
};

class Person {
public:
	//m_pen (name)  相当于采用隐式转换法 Pen m_pname=name
	Person (int sex,string name) :m_sex(sex),m_pen(name) //初始化列表
	{		
		cout << "person的构造函数调用" << endl;
	}

	pen m_pen;			//笔名
	int m_sex;		//性别
};


.8静态成员

静态成员变量

  1. 所有对象共享同一份数据,指向同一数据
  2. 编译阶段分配内存
  3. 类内声明,类外初始化数据类型 类名::成员变量名=
class Person {
public:

	static int m_sex;		//性别
};

int Person::m_sex = 1;		//类外初始化

void test1() {
	//静态成员的访问方式
	//1,通过对象访问
	//Person p
	//cout <<p.m_sex<<endl;
	
	//2.通过类名进行访问
	cout << Person::m_sex << endl;		//但私有权限下的无法通过类名访问到
}

静态成员函数

  1. 所有对象共享同一个函数
  2. 静态成员函数只能访问静态成员变量
  3. 私有权限类外无法访问静态成员函数,只能通过对象访问
class Person {
public:

	static void fun() {
		m_sex = 1;			//可以访问静态成员变量
		//b = 20;			//无法访问非静态,无法区分是哪个对象的成员变量
	}
	static int m_sex;		//性别
	int b;
};

int Person::m_sex = 1;		//类外初始化
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值