对象和成员函数

一、对象的创建和销毁过程分析

1、对象的创建过程

①给对象划分空间(堆、栈)

②执行初始化列表

Ⅰ. 根据继承表的顺序调用父类的无参构造或者有参构造
	通过 :父类名(val)	调用父类的有参构造
Ⅱ. 根据成员变量的定义顺序调用类类型成员的无参构造或者有参构造
	通过 :类类型成员名(val)	调用类类型成员的有参构造
Ⅲ. 对其他成员进行初始化

③执行自己的构造函数、可能去申请资源

2、对象的销毁过程

①执行自己的析构函数、可能释放资源

②根据类类型成员顺序的逆序,调用它们的析构函数

③根据继承表的逆序,调用父类的析构函数

④释放对象的内存

二、成员函数是如何区分调用它的对象-使用隐藏的this指针

①对象的内存只存储了成员变量,没有存储成员函数指针,相当于所有对象调用的是同一份成员函数

②当对象调用成员函数时,编译器会自动把对象的地址传递给该成员函数,也就是说普通的成员函数中都有一个隐藏的函数,该参数名字叫做this指针,this指针用来接收调用对象的地址

③this指针拿到了调用对象的地址后,就可以直接访问该对象的成员,完成区分对象的任务

④虽然this指针是隐藏定义的,但是可以显式地使用它,但不要多此一举的显式定义它

class Student
{
	char name[20];
	char sex;
	int id;
public:
	Student(const char* name,char sex,int id):sex(sex),id(id)
	{
		strcpy(this->name,name);
		cout << "构造函数" << endl; 	
	}
};

三、常函数

①被const修饰了this指针的成员函数,称为常函数

②当对象调用成员函数时,编译器会隐式地把对象地址传递给成员函数

③当对象被const修饰过具有常属性,就不能直接调用普通成员函数,因为传递的对象地址也具有常属性,而普通成员函数的this指针参数不具备常属性,所以编译器会报错,C++编译器不允许用带常属性的指针数据给不带常属性的指针变量赋值

④因此需要让成员函数中的this也具备常属性,通过const修饰变成常函数,所以const其实修饰的是this指针,这样就可以让具有常属性的对象调用常函数

返回值 类名::成员函数(参数列表)const
{
	//	常函数
}

⑤具有常属性的对象只能调用常函数,常函数中也只能调用常函数,不具有常属性的对象都可以调用

⑥同名的成员函数,如果其他参数列表完全相同,但是常属性不同,可以构成重载

void func(void)const
{
	sex = 'q';
	cout << "func" << endl;	
}
void func(void)
{
	sex = 'x';
	cout << "func2" << endl;	
}

⑦正常来说在常函数中是不能修改成员变量的,除非该成员在定义时通过mutable修饰

相关问题

1、const在C和C++中的相同点和不同点

相同点:

const在C和C++中都用来**“显式”**地保护数据不被修改

不同点:

①C++编译器会优化const变量的取值过程,哪怕该变量的内存被强行修改也不会改变通过变量访问的数据,这种机制会更安全,但是C语言编译器不会优化

②在C++中const还可以用于修饰成员函数的this指针,从而定义常函数

2、一个空的结构体在C语言和C++中分别占多少个字节?为什么

在C语言中空结构体占0字节

在C++中空结构体占1字节

在C++结构体中可以定义成员函数,并且默认有四个隐藏的成员函数(构造、析构、拷贝构造、赋值),当对象去调用成员函数时,需要传递对象的地址给成员函数,这种机制就要求结构对象需要在内存中有一席之地,所以如果结构没有任何的成员变量,编译器会让结构至少拥有1字节的不使用内存,让上面这套机制自洽

四、拷贝构造

拷贝构造就是一种特殊版本的构造函数,格式为

类名(const 类名& that)	
{
    //	执行给每个成员变量进行赋值
}
1、什么时候会调用拷贝构造

当使用旧对象给新对象初始化时,会自动调用拷贝构造

Test t1;		//	调用无参构造
Test t2 = t1;	//	调用拷贝构造
Test t3(t2);	//	调用拷贝构造

拷贝构造的任务:

负责把旧对象中的成员变量拷贝给新对象,并且编译器默认已经自动生成具有该功能的拷贝构造函数

2、什么时候需要显式地写拷贝构造

普通情况下编译器自动生成的拷贝构造完全够用,但当类中有成员是指针类型且为该指针成员分配了堆内存,使用默认自动生成的拷贝构造只会对指针的值进行拷贝,此时就会导致两个对象的指针成员指向同一块内存,所以在执行析构函数时会造成重复释放

class Student
{
	char* name;
	char sex;
	int id;
public:
	Student(const char* name,char sex,int id):sex(sex),id(id)
	{
		int len = strlen(name);
		this->name = new char[len+1];
		strcpy(this->name,name);	
	}
	~Student(void)
	{
		delete[] name;	//	会导致重复释放
	}
};
3、浅拷贝和深拷贝

浅拷贝:当类中的成员有指针且分配堆内存,只拷贝指针变量的值

深拷贝:不拷贝指针变量的值,而是拷贝指针变量所指向的内存的内容

Student(const Student& that)
{
	//	name = that.name;	//	自动生成 浅拷贝
	int len = strlen(that.name);
	name = new char[len+1];
	strcpy(name,that.name);	//	深拷贝
	sex = that.sex;
	id = that.id;
	cout << "拷贝构造" << endl;
}

五、赋值操作(拷贝赋值、赋值运算符函数)

任务:就是用一个旧对象给另一个旧对象赋值(两个对象都已经完成创建)

注意:在C++中会把运算符当做函数处理,使用运算符时会调用运算符函数

Test t1,t2,t3;		//	无参构造
t3 = t1 = t2;		//	赋值操作函数

类名& operator=(const 类名& that)
{
    
}
1、什么时候需要显式地写赋值操作

普通情况一般不需要显式地写赋值操作

类似于需要显示地写拷贝构造一样,当需要进行深拷贝时,就需要显式地写拷贝构造和赋值操作

2、实现赋值操作需要注意的问题

虽然赋值操作与拷贝构造的任务相同,都需要深拷贝,但是环境有所不同(旧对象、新对象)

问题1:被赋值的对象的指针已经分配有内存

①先释放被赋值者的指针指向的原内存

②根据赋值者的赋值重新申请新内存

③把赋值者内存的内容深拷贝到新内存中

问题2:可能出现对象自己给自己赋值的情况

通过判断this指针与赋值者的地址是否相同,如果相同立即返回*this结束,如果不相同才进行赋值操作

Student& operator=(const Student& that)
{
	if(&that != this)
	{
		delete[] name;
		int len = strlen(that.name);
		name = new char[len+1];
		strcpy(name,that.name);	//	深拷贝
		sex = that.sex;
		id = that.id;
		cout << "赋值操作" << endl;
	}
	return *this;
}
实现一个类似于string的类,String的四个成员函数
#include <iostream>
#include <cstring>
using namespace std;

class String
{
	char* str;
public:
	String(const char* str="")
	{
		this->str = new char[strlen(str)+1];
		strcpy(this->str,str);
	}
	String(const String& that)
	{
		str = new char[strlen(that.str)+1];
		strcpy(str,that.str);
	}
	~String(void)
	{
		delete[] str;
	}

	String& operator=(const String& that)
	{
		if(this != &that)
		{
			delete[] str;
			str = new char[strlen(that.str)+1];
			strcpy(str,that.str);
		}
		return *this;
	}

	void show(void)
	{
		cout << str << endl;	
	}
};

int main(int argc,const char* argv[])
{
	String str("hehe");
	str.show();
	String str1 = str;
	str1.show();
	String str2("xixi");
	str2 = str;
	str2.show();
	//cout << str << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值